diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 31ade0bdbe4353cd88c8f2f5263804d2ab3a0b96..d062c1d8cef91b6bb4279ff1541348923e6acdd5 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -425,15 +425,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 77434f410aeed3daaac6603a055aab7d09046d4e..83dd14740818e201c4b44f3b183ed5872ffb81d8 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -592,35 +592,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/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index e9072b76efcfa11107a19b64db7462c557a8efe5..7a2c45af38289b363ad034554666d55a31465b3c 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -3952,8 +3952,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 6192d1fe8958e98b24d2e97dfdaa0d8a24561e12..7995235d9fa3b8988b9efff185c80536c5c49dd9 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 270e8fbb14bcf2c948959bfc425c6cfde0b98b96..dbf3a20ed91cd2dd869ecddc1edc9561dc550be6 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -104,6 +104,20 @@ extern int	ssl_renegotiation_limit;
  * 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
@@ -116,12 +130,8 @@ 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 */
+	int			remote_hostname_errcode;		/* see above */
 	char	   *remote_port;	/* text rep of remote port */
 	CAC_state	canAcceptConnections;	/* postmaster connection status */
 
diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c
index 52a20c5c2ccfef56224229633f6305b0c099b57e..7880ad8a16ea0bbe930b94d4345dd0cf305abcc5 100644
--- a/src/port/getaddrinfo.c
+++ b/src/port/getaddrinfo.c
@@ -181,7 +181,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
 		{
@@ -347,8 +347,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
@@ -375,6 +375,10 @@ getnameinfo(const struct sockaddr * sa, int salen,
 		return EAI_FAMILY;
 #endif
 
+	/* Unsupported flags. */
+	if (flags & NI_NAMEREQD)
+		return EAI_AGAIN;
+
 	if (node)
 	{
 		if (sa->sa_family == AF_INET)
@@ -397,7 +401,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;
 	}