diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index b9664cb05e70b670ae4126c49a77e675f8e458cf..0a431fc71fee85c6ce07af99480aef2ff0524739 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -229,14 +229,15 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
      <term><replaceable>address</replaceable></term>
      <listitem>
       <para>
-       Specifies the client machine addresses that this record
+       Specifies the client machine address(es) that this record
        matches.  This field can contain either a host name, an IP
        address range, or one of the special key words mentioned below.
       </para>
 
       <para>
-       An IP address is specified in standard dotted decimal
-       notation with a <acronym>CIDR</> mask length.  The mask
+       An IP address range is specified using standard numeric notation
+       for the range's starting address, then a slash (<literal>/</literal>)
+       and a <acronym>CIDR</> mask length.  The mask
        length indicates the number of high-order bits of the client
        IP address that must match.  Bits to the right of this should
        be zero in the given IP address.
@@ -245,25 +246,27 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
       </para>
 
       <para>
-       Typical examples of an IP address range specified this way are
+       Typical examples of an IPv4 address range specified this way are
        <literal>172.20.143.89/32</literal> for a single host, or
        <literal>172.20.143.0/24</literal> for a small network, or
        <literal>10.6.0.0/16</literal> for a larger one.
+       An IPv6 address range might look like <literal>::1/128</literal>
+       for a single host (in this case the IPv6 loopback address) or
+       <literal>fe80::7a31:c1ff:0000:0000/96</literal> for a small
+       network.
        <literal>0.0.0.0/0</literal> represents all
-       IPv4 addresses, and <literal>::/0</literal> represents
+       IPv4 addresses, and <literal>::0/0</literal> represents
        all IPv6 addresses.
-       To specify a single host, use a CIDR mask of 32 for IPv4 or
+       To specify a single host, use a mask length of 32 for IPv4 or
        128 for IPv6.  In a network address, do not omit trailing zeroes.
       </para>
 
       <para>
-       An IP address given in IPv4 format will match IPv6 connections that
-       have the corresponding address, for example <literal>127.0.0.1</>
-       will match the IPv6 address <literal>::ffff:127.0.0.1</>.  An entry
-       given in IPv6 format will match only IPv6 connections, even if the
-       represented address is in the IPv4-in-IPv6 range.  Note that entries
-       in IPv6 format will be rejected if the system's C library does not have
-       support for IPv6 addresses.
+       An entry given in IPv4 format will match only IPv4 connections,
+       and an entry given in IPv6 format will match only IPv6 connections,
+       even if the represented address is in the IPv4-in-IPv6 range.
+       Note that entries in IPv6 format will be rejected if the system's
+       C library does not have support for IPv6 addresses.
       </para>
 
       <para>
@@ -275,7 +278,7 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
 
       <para>
        If a host name is specified (anything that is not an IP address
-       or a special key word is processed as a potential host name),
+       range or a special key word is treated as a host name),
        that name is compared with the result of a reverse name
        resolution of the client's IP address (e.g., reverse DNS
        lookup, if DNS is used).  Host name comparisons are case
@@ -353,8 +356,9 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
      <term><replaceable>IP-mask</replaceable></term>
      <listitem>
       <para>
-       These fields can be used as an alternative to the
-       <replaceable>CIDR-address</replaceable> notation. Instead of
+       These two fields can be used as an alternative to the
+       <replaceable>IP-address</><literal>/</><replaceable>mask-length</>
+       notation.  Instead of
        specifying the mask length, the actual mask is specified in a
        separate column. For example, <literal>255.0.0.0</> represents an IPv4
        CIDR mask length of 8, and <literal>255.255.255.255</> represents a
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 7106f0871f966f457906a460a427a6f0d3c713a1..49b2ea94db43da4650b7058455e50f5e6a3c624b 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -653,42 +653,12 @@ check_hostname(hbaPort *port, const char *hostname)
 static bool
 check_ip(SockAddr *raddr, struct sockaddr * addr, struct sockaddr * mask)
 {
-	if (raddr->addr.ss_family == addr->sa_family)
-	{
-		/* Same address family */
-		if (!pg_range_sockaddr(&raddr->addr,
-							   (struct sockaddr_storage *) addr,
-							   (struct sockaddr_storage *) mask))
-			return false;
-	}
-#ifdef HAVE_IPV6
-	else if (addr->sa_family == AF_INET &&
-			 raddr->addr.ss_family == AF_INET6)
-	{
-		/*
-		 * If we're connected on IPv6 but the file specifies an IPv4 address
-		 * to match against, promote the latter to an IPv6 address before
-		 * trying to match the client's address.
-		 */
-		struct sockaddr_storage addrcopy,
-					maskcopy;
-
-		memcpy(&addrcopy, addr, sizeof(addrcopy));
-		memcpy(&maskcopy, mask, sizeof(maskcopy));
-		pg_promote_v4_to_v6_addr(&addrcopy);
-		pg_promote_v4_to_v6_mask(&maskcopy);
-
-		if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
-			return false;
-	}
-#endif   /* HAVE_IPV6 */
-	else
-	{
-		/* Wrong address family, no IPV6 */
-		return false;
-	}
-
-	return true;
+	if (raddr->addr.ss_family == addr->sa_family &&
+		pg_range_sockaddr(&raddr->addr,
+						  (struct sockaddr_storage *) addr,
+						  (struct sockaddr_storage *) mask))
+		return true;
+	return false;
 }
 
 /*
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
index 76d671303ed76f7f972e7f0edecb4073d0325ad8..56514614326ea88232278c8ae9d7e1536406a3bc 100644
--- a/src/backend/libpq/ip.c
+++ b/src/backend/libpq/ip.c
@@ -407,79 +407,6 @@ pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
 }
 
 
-#ifdef HAVE_IPV6
-
-/*
- * pg_promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
- *		the standard convention for IPv4 addresses mapped into IPv6 world
- *
- * The passed addr is modified in place; be sure it is large enough to
- * hold the result!  Note that we only worry about setting the fields
- * that pg_range_sockaddr will look at.
- */
-void
-pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr)
-{
-	struct sockaddr_in addr4;
-	struct sockaddr_in6 addr6;
-	uint32		ip4addr;
-
-	memcpy(&addr4, addr, sizeof(addr4));
-	ip4addr = ntohl(addr4.sin_addr.s_addr);
-
-	memset(&addr6, 0, sizeof(addr6));
-
-	addr6.sin6_family = AF_INET6;
-
-	addr6.sin6_addr.s6_addr[10] = 0xff;
-	addr6.sin6_addr.s6_addr[11] = 0xff;
-	addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
-	addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
-	addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
-	addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
-
-	memcpy(addr, &addr6, sizeof(addr6));
-}
-
-/*
- * pg_promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
- *		the standard convention for IPv4 addresses mapped into IPv6 world
- *
- * This must be different from pg_promote_v4_to_v6_addr because we want to
- * set the high-order bits to 1's not 0's.
- *
- * The passed addr is modified in place; be sure it is large enough to
- * hold the result!  Note that we only worry about setting the fields
- * that pg_range_sockaddr will look at.
- */
-void
-pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr)
-{
-	struct sockaddr_in addr4;
-	struct sockaddr_in6 addr6;
-	uint32		ip4addr;
-	int			i;
-
-	memcpy(&addr4, addr, sizeof(addr4));
-	ip4addr = ntohl(addr4.sin_addr.s_addr);
-
-	memset(&addr6, 0, sizeof(addr6));
-
-	addr6.sin6_family = AF_INET6;
-
-	for (i = 0; i < 12; i++)
-		addr6.sin6_addr.s6_addr[i] = 0xff;
-
-	addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
-	addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
-	addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
-	addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
-
-	memcpy(addr, &addr6, sizeof(addr6));
-}
-#endif   /* HAVE_IPV6 */
-
-
 /*
  * Run the callback function for the addr/mask, after making sure the
  * mask is sane for the addr.
diff --git a/src/include/libpq/ip.h b/src/include/libpq/ip.h
index 0ea57461fc17ae110f6fd0bcdc9983d3a52ea8df..c528e595e5e3d0bcba57e64d78f8f023d928e3f4 100644
--- a/src/include/libpq/ip.h
+++ b/src/include/libpq/ip.h
@@ -46,11 +46,6 @@ extern int pg_range_sockaddr(const struct sockaddr_storage * addr,
 extern int pg_sockaddr_cidr_mask(struct sockaddr_storage * mask,
 					  char *numbits, int family);
 
-#ifdef HAVE_IPV6
-extern void pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr);
-extern void pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr);
-#endif
-
 extern int	pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data);
 
 #endif   /* IP_H */