diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 9cdee2bb3e7bd2e42a6de3e37b006786066fe543..c65427e53c49dad46790b84a6504ad6b77779a84 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -440,15 +440,25 @@ ClientAuthentication(Port *port)
 								   NI_NUMERICHOST);
 
 #define HOSTNAME_LOOKUP_DETAIL(port) \
-				(port->remote_hostname				  \
-				 ? (port->remote_hostname_resolv == +1					\
-					? errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", port->remote_hostname) \
-					: (port->remote_hostname_resolv == 0				\
-					   ? errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", port->remote_hostname) \
-					   : (port->remote_hostname_resolv == -1			\
-						  ? errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", port->remote_hostname) \
-						  : 0)))										\
-				 : 0)
+				(port->remote_hostname ? \
+				 (port->remote_hostname_resolv == +1 ? \
+				  errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", \
+								port->remote_hostname) : \
+				  port->remote_hostname_resolv == 0 ? \
+				  errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", \
+								port->remote_hostname) : \
+				  port->remote_hostname_resolv == -1 ? \
+				  errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", \
+								port->remote_hostname) : \
+				  port->remote_hostname_resolv == -2 ? \
+				  errdetail_log("Could not translate client host name \"%s\" to IP address: %s.", \
+								port->remote_hostname, \
+								gai_strerror(port->remote_hostname_errcode)) : \
+				  0) \
+				 : (port->remote_hostname_resolv == -2 ? \
+					errdetail_log("Could not resolve client IP address to a host name: %s.", \
+								  gai_strerror(port->remote_hostname_errcode)) : \
+					0))
 
 				if (am_walsender)
 				{
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 828f6dcc8e1653ad25f206f9d10b55006466b2e1..09e8715c798ec24c8596e78ef45f930f350109e6 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -565,35 +565,47 @@ check_hostname(hbaPort *port, const char *hostname)
 	int			ret;
 	bool		found;
 
+	/* Quick out if remote host name already known bad */
+	if (port->remote_hostname_resolv < 0)
+		return false;
+
 	/* Lookup remote host name if not already done */
 	if (!port->remote_hostname)
 	{
 		char		remote_hostname[NI_MAXHOST];
 
-		if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
-							   remote_hostname, sizeof(remote_hostname),
-							   NULL, 0,
-							   0) != 0)
+		ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
+								 remote_hostname, sizeof(remote_hostname),
+								 NULL, 0,
+								 NI_NAMEREQD);
+		if (ret != 0)
+		{
+			/* remember failure; don't complain in the postmaster log yet */
+			port->remote_hostname_resolv = -2;
+			port->remote_hostname_errcode = ret;
 			return false;
+		}
 
 		port->remote_hostname = pstrdup(remote_hostname);
 	}
 
+	/* Now see if remote host name matches this pg_hba line */
 	if (!hostname_match(hostname, port->remote_hostname))
 		return false;
 
-	/* Lookup IP from host name and check against original IP */
-
+	/* If we already verified the forward lookup, we're done */
 	if (port->remote_hostname_resolv == +1)
 		return true;
-	if (port->remote_hostname_resolv == -1)
-		return false;
 
+	/* Lookup IP from host name and check against original IP */
 	ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
 	if (ret != 0)
-		ereport(ERROR,
-				(errmsg("could not translate host name \"%s\" to address: %s",
-						port->remote_hostname, gai_strerror(ret))));
+	{
+		/* remember failure; don't complain in the postmaster log yet */
+		port->remote_hostname_resolv = -2;
+		port->remote_hostname_errcode = ret;
+		return false;
+	}
 
 	found = false;
 	for (gai = gai_result; gai; gai = gai->ai_next)
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
index 550e11b68cf99683f33c9bb9dba1ab10b634c3c8..db3a5252efd4e21eb59a0168c1dfa75577c9d179 100644
--- a/src/backend/libpq/ip.c
+++ b/src/backend/libpq/ip.c
@@ -247,11 +247,6 @@ getnameinfo_unix(const struct sockaddr_un * sa, int salen,
 		(node == NULL && service == NULL))
 		return EAI_FAIL;
 
-	/* We don't support those. */
-	if ((node && !(flags & NI_NUMERICHOST))
-		|| (service && !(flags & NI_NUMERICSERV)))
-		return EAI_FAIL;
-
 	if (node)
 	{
 		ret = snprintf(node, nodelen, "%s", "[local]");
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index b96b505834a19e9888c2ae7d2ffb4d8341d43a6f..95640622bc1730c2064efb4a4e3f90b7a6024263 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -3381,6 +3381,7 @@ static void
 BackendInitialize(Port *port)
 {
 	int			status;
+	int			ret;
 	char		remote_host[NI_MAXHOST];
 	char		remote_port[NI_MAXSERV];
 	char		remote_ps_data[NI_MAXHOST];
@@ -3442,21 +3443,13 @@ BackendInitialize(Port *port)
 	 */
 	remote_host[0] = '\0';
 	remote_port[0] = '\0';
-	if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
+	if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
 						   remote_host, sizeof(remote_host),
 						   remote_port, sizeof(remote_port),
-				  (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV) != 0)
-	{
-		int			ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
-											 remote_host, sizeof(remote_host),
-											 remote_port, sizeof(remote_port),
-											 NI_NUMERICHOST | NI_NUMERICSERV);
-
-		if (ret != 0)
-			ereport(WARNING,
-					(errmsg_internal("pg_getnameinfo_all() failed: %s",
-									 gai_strerror(ret))));
-	}
+				  (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0)
+		ereport(WARNING,
+				(errmsg_internal("pg_getnameinfo_all() failed: %s",
+								 gai_strerror(ret))));
 	if (remote_port[0] == '\0')
 		snprintf(remote_ps_data, sizeof(remote_ps_data), "%s", remote_host);
 	else
@@ -3480,8 +3473,23 @@ BackendInitialize(Port *port)
 	 */
 	port->remote_host = strdup(remote_host);
 	port->remote_port = strdup(remote_port);
-	if (log_hostname)
-		port->remote_hostname = port->remote_host;
+
+	/*
+	 * If we did a reverse lookup to name, we might as well save the results
+	 * rather than possibly repeating the lookup during authentication.
+	 *
+	 * Note that we don't want to specify NI_NAMEREQD above, because then we'd
+	 * get nothing useful for a client without an rDNS entry.  Therefore, we
+	 * must check whether we got a numeric IPv4 or IPv6 address, and not save
+	 * it into remote_hostname if so.  (This test is conservative and might
+	 * sometimes classify a hostname as numeric, but an error in that
+	 * direction is safe; it only results in a possible extra lookup.)
+	 */
+	if (log_hostname &&
+		ret == 0 &&
+		strspn(remote_host, "0123456789.") < strlen(remote_host) &&
+		strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
+		port->remote_hostname = strdup(remote_host);
 
 	/*
 	 * Ready to begin client interaction.  We will give up and exit(1) after a
diff --git a/src/include/getaddrinfo.h b/src/include/getaddrinfo.h
index 519a97975ef63e0c21f13893b3baacb1bde0e23f..9adceb4575ffe396a44ba5ea16c2ce5c245e0cec 100644
--- a/src/include/getaddrinfo.h
+++ b/src/include/getaddrinfo.h
@@ -82,6 +82,9 @@
 #ifndef NI_NUMERICSERV
 #define NI_NUMERICSERV	2
 #endif
+#ifndef NI_NAMEREQD
+#define NI_NAMEREQD		4
+#endif
 
 #ifndef NI_MAXHOST
 #define NI_MAXHOST	1025
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 4d92c18974bc56b402445671e4ff84d7c7628daa..95b538c64db23fcac57ab39cbdfb6e587ba09e72 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -99,6 +99,20 @@ typedef struct
  * still available when a backend is running (see MyProcPort).	The data
  * it points to must also be malloc'd, or else palloc'd in TopMemoryContext,
  * so that it survives into PostgresMain execution!
+ *
+ * remote_hostname is set if we did a successful reverse lookup of the
+ * client's IP address during connection setup.
+ * remote_hostname_resolv tracks the state of hostname verification:
+ *	+1 = remote_hostname is known to resolve to client's IP address
+ *	-1 = remote_hostname is known NOT to resolve to client's IP address
+ *	 0 = we have not done the forward DNS lookup yet
+ *	-2 = there was an error in name resolution
+ * If reverse lookup of the client IP address fails, remote_hostname will be
+ * left NULL while remote_hostname_resolv is set to -2.  If reverse lookup
+ * succeeds but forward lookup fails, remote_hostname_resolv is also set to -2
+ * (the case is distinguishable because remote_hostname isn't NULL).  In
+ * either of the -2 cases, remote_hostname_errcode saves the lookup return
+ * code for possible later use with gai_strerror.
  */
 
 typedef struct Port
@@ -111,12 +125,7 @@ typedef struct Port
 	char	   *remote_host;	/* name (or ip addr) of remote host */
 	char	   *remote_hostname;/* name (not ip addr) of remote host, if
 								 * available */
-	int			remote_hostname_resolv; /* +1 = remote_hostname is known to
-										 * resolve to client's IP address; -1
-										 * = remote_hostname is known NOT to
-										 * resolve to client's IP address; 0 =
-										 * we have not done the forward DNS
-										 * lookup yet */
+	int			remote_hostname_resolv; /* see above */
 	char	   *remote_port;	/* text rep of remote port */
 	CAC_state	canAcceptConnections;	/* postmaster connection status */
 
@@ -178,6 +187,9 @@ typedef struct Port
 	char	   *peer_cn;
 	unsigned long count;
 #endif
+
+	/* This field will be in a saner place in 9.4 and up */
+	int			remote_hostname_errcode;		/* see above */
 } Port;
 
 
diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c
index c117012ec7eadf8ea87c254a55c08a4372e3d9a2..3d23ffecaa33d56794758dcd2cb82099dc3dfd91 100644
--- a/src/port/getaddrinfo.c
+++ b/src/port/getaddrinfo.c
@@ -182,7 +182,7 @@ getaddrinfo(const char *node, const char *service,
 		else if (hints.ai_flags & AI_NUMERICHOST)
 		{
 			if (!inet_aton(node, &sin.sin_addr))
-				return EAI_FAIL;
+				return EAI_NONAME;
 		}
 		else
 		{
@@ -349,8 +349,8 @@ gai_strerror(int errcode)
 /*
  * Convert an ipv4 address to a hostname.
  *
- * Bugs:	- Only supports NI_NUMERICHOST and NI_NUMERICSERV
- *		  It will never resolv a hostname.
+ * Bugs:	- Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
+ *		  It will never resolve a hostname.
  *		- No IPv6 support.
  */
 int
@@ -373,16 +373,15 @@ getnameinfo(const struct sockaddr * sa, int salen,
 	if (sa == NULL || (node == NULL && service == NULL))
 		return EAI_FAIL;
 
-	/* We don't support those. */
-	if ((node && !(flags & NI_NUMERICHOST))
-		|| (service && !(flags & NI_NUMERICSERV)))
-		return EAI_FAIL;
-
 #ifdef	HAVE_IPV6
 	if (sa->sa_family == AF_INET6)
 		return EAI_FAMILY;
 #endif
 
+	/* Unsupported flags. */
+	if (flags & NI_NAMEREQD)
+		return EAI_AGAIN;
+
 	if (node)
 	{
 		if (sa->sa_family == AF_INET)
@@ -405,7 +404,7 @@ getnameinfo(const struct sockaddr * sa, int salen,
 			ret = snprintf(service, servicelen, "%d",
 						   ntohs(((struct sockaddr_in *) sa)->sin_port));
 		}
-		if (ret == -1 || ret > servicelen)
+		if (ret == -1 || ret >= servicelen)
 			return EAI_MEMORY;
 	}