diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 9a266beb5d..efc53f3135 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -18,6 +18,7 @@
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <pwd.h>
 #include <unistd.h>
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index f210ccbde8..3503605a7d 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -10,6 +10,7 @@
 #include <ctype.h>
 #include <limits.h>
 #include <math.h>
+#include <pwd.h>
 #include <signal.h>
 #ifndef WIN32
 #include <unistd.h>				/* for write() */
diff --git a/src/include/port.h b/src/include/port.h
index 56e3721f6a..3d103a2b31 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -14,8 +14,6 @@
 #define PG_PORT_H
 
 #include <ctype.h>
-#include <netdb.h>
-#include <pwd.h>
 
 /*
  * Windows has enough specialized port stuff that we push most of it off
@@ -484,18 +482,12 @@ extern char *dlerror(void);
 #define RTLD_GLOBAL 0
 #endif
 
-/* thread.h */
+/* thread.c */
 #ifndef WIN32
-extern int	pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
-					   size_t buflen, struct passwd **result);
+extern bool pg_get_user_name(uid_t user_id, char *buffer, size_t buflen);
+extern bool pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen);
 #endif
 
-extern int	pqGethostbyname(const char *name,
-							struct hostent *resultbuf,
-							char *buffer, size_t buflen,
-							struct hostent **result,
-							int *herrno);
-
 extern void pg_qsort(void *base, size_t nel, size_t elsize,
 					 int (*cmp) (const void *, const void *));
 extern int	pg_qsort_strcmp(const void *a, const void *b);
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 82fc7cdb98..2edc3f48e2 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -35,7 +35,6 @@
 #ifndef  MAXHOSTNAMELEN
 #include <netdb.h>				/* for MAXHOSTNAMELEN on some */
 #endif
-#include <pwd.h>
 #endif
 
 #include "common/md5.h"
@@ -1099,14 +1098,17 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
 
 
 /*
- * pg_fe_getauthname
+ * pg_fe_getusername
  *
- * Returns a pointer to malloc'd space containing whatever name the user
- * has authenticated to the system.  If there is an error, return NULL,
- * and append a suitable error message to *errorMessage if that's not NULL.
+ * Returns a pointer to malloc'd space containing the name of the
+ * specified user_id.  If there is an error, return NULL, and append
+ * a suitable error message to *errorMessage if that's not NULL.
+ *
+ * Caution: on Windows, the user_id argument is ignored, and we always
+ * fetch the current user's name.
  */
 char *
-pg_fe_getauthname(PQExpBuffer errorMessage)
+pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage)
 {
 	char	   *result = NULL;
 	const char *name = NULL;
@@ -1116,17 +1118,13 @@ pg_fe_getauthname(PQExpBuffer errorMessage)
 	char		username[256 + 1];
 	DWORD		namesize = sizeof(username);
 #else
-	uid_t		user_id = geteuid();
 	char		pwdbuf[BUFSIZ];
-	struct passwd pwdstr;
-	struct passwd *pw = NULL;
-	int			pwerr;
 #endif
 
 	/*
 	 * Some users are using configure --enable-thread-safety-force, so we
 	 * might as well do the locking within our library to protect
-	 * pqGetpwuid(). In fact, application developers can use getpwuid() in
+	 * getpwuid(). In fact, application developers can use getpwuid() in
 	 * their application if they use the locking call we provide, or install
 	 * their own locking function using PQregisterThreadLock().
 	 */
@@ -1140,21 +1138,10 @@ pg_fe_getauthname(PQExpBuffer errorMessage)
 						  libpq_gettext("user name lookup failure: error code %lu\n"),
 						  GetLastError());
 #else
-	pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
-	if (pw != NULL)
-		name = pw->pw_name;
+	if (pg_get_user_name(user_id, pwdbuf, sizeof(pwdbuf)))
+		name = pwdbuf;
 	else if (errorMessage)
-	{
-		if (pwerr != 0)
-			appendPQExpBuffer(errorMessage,
-							  libpq_gettext("could not look up local user ID %d: %s\n"),
-							  (int) user_id,
-							  strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
-		else
-			appendPQExpBuffer(errorMessage,
-							  libpq_gettext("local user with ID %d does not exist\n"),
-							  (int) user_id);
-	}
+		appendPQExpBuffer(errorMessage, "%s\n", pwdbuf);
 #endif
 
 	if (name)
@@ -1170,6 +1157,23 @@ pg_fe_getauthname(PQExpBuffer errorMessage)
 	return result;
 }
 
+/*
+ * pg_fe_getauthname
+ *
+ * Returns a pointer to malloc'd space containing whatever name the user
+ * has authenticated to the system.  If there is an error, return NULL,
+ * and append a suitable error message to *errorMessage if that's not NULL.
+ */
+char *
+pg_fe_getauthname(PQExpBuffer errorMessage)
+{
+#ifdef WIN32
+	return pg_fe_getusername(0, errorMessage);
+#else
+	return pg_fe_getusername(geteuid(), errorMessage);
+#endif
+}
+
 
 /*
  * PQencryptPassword -- exported routine to encrypt a password with MD5
diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h
index 16d5e1da0f..f22b3fe648 100644
--- a/src/interfaces/libpq/fe-auth.h
+++ b/src/interfaces/libpq/fe-auth.h
@@ -20,6 +20,7 @@
 
 /* Prototypes for functions in fe-auth.c */
 extern int	pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn);
+extern char *pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage);
 extern char *pg_fe_getauthname(PQExpBuffer errorMessage);
 
 /* Mechanisms in fe-auth-scram.c */
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index a12e0180fd..5fc16be849 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2813,10 +2813,7 @@ keep_going:						/* We will come back to here until there is
 					IS_AF_UNIX(conn->raddr.addr.ss_family))
 				{
 #ifndef WIN32
-					char		pwdbuf[BUFSIZ];
-					struct passwd pass_buf;
-					struct passwd *pass;
-					int			passerr;
+					char	   *remote_username;
 #endif
 					uid_t		uid;
 					gid_t		gid;
@@ -2839,28 +2836,20 @@ keep_going:						/* We will come back to here until there is
 					}
 
 #ifndef WIN32
-					passerr = pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
-					if (pass == NULL)
-					{
-						if (passerr != 0)
-							appendPQExpBuffer(&conn->errorMessage,
-											  libpq_gettext("could not look up local user ID %d: %s\n"),
-											  (int) uid,
-											  strerror_r(passerr, sebuf, sizeof(sebuf)));
-						else
-							appendPQExpBuffer(&conn->errorMessage,
-											  libpq_gettext("local user with ID %d does not exist\n"),
-											  (int) uid);
-						goto error_return;
-					}
+					remote_username = pg_fe_getusername(uid,
+														&conn->errorMessage);
+					if (remote_username == NULL)
+						goto error_return;	/* message already logged */
 
-					if (strcmp(pass->pw_name, conn->requirepeer) != 0)
+					if (strcmp(remote_username, conn->requirepeer) != 0)
 					{
 						appendPQExpBuffer(&conn->errorMessage,
 										  libpq_gettext("requirepeer specifies \"%s\", but actual peer user name is \"%s\"\n"),
-										  conn->requirepeer, pass->pw_name);
+										  conn->requirepeer, remote_username);
+						free(remote_username);
 						goto error_return;
 					}
+					free(remote_username);
 #else							/* WIN32 */
 					/* should have failed with ENOSYS above */
 					Assert(false);
@@ -7271,16 +7260,7 @@ pqGetHomeDirectory(char *buf, int bufsize)
 
 	home = getenv("HOME");
 	if (home == NULL || home[0] == '\0')
-	{
-		char		pwdbuf[BUFSIZ];
-		struct passwd pwdstr;
-		struct passwd *pwd = NULL;
-
-		(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
-		if (pwd == NULL)
-			return false;
-		home = pwd->pw_dir;
-	}
+		return pg_get_user_home_dir(geteuid(), buf, bufsize);
 	strlcpy(buf, home, bufsize);
 	return true;
 #else
diff --git a/src/port/Makefile b/src/port/Makefile
index b3754d8940..bfe1feb0d4 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -84,6 +84,10 @@ libpgport.a: $(OBJS)
 	rm -f $@
 	$(AR) $(AROPT) $@ $^
 
+# getaddrinfo.o and getaddrinfo_shlib.o need PTHREAD_CFLAGS (but getaddrinfo_srv.o does not)
+getaddrinfo.o: CFLAGS+=$(PTHREAD_CFLAGS)
+getaddrinfo_shlib.o: CFLAGS+=$(PTHREAD_CFLAGS)
+
 # thread.o and thread_shlib.o need PTHREAD_CFLAGS (but thread_srv.o does not)
 thread.o: CFLAGS+=$(PTHREAD_CFLAGS)
 thread_shlib.o: CFLAGS+=$(PTHREAD_CFLAGS)
diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c
index b0ca4c778e..3284c6eb52 100644
--- a/src/port/getaddrinfo.c
+++ b/src/port/getaddrinfo.c
@@ -34,6 +34,14 @@
 #include "port/pg_bswap.h"
 
 
+#ifdef FRONTEND
+static int	pqGethostbyname(const char *name,
+							struct hostent *resultbuf,
+							char *buffer, size_t buflen,
+							struct hostent **result,
+							int *herrno);
+#endif
+
 #ifdef WIN32
 /*
  * The native routines may or may not exist on the Windows platform we are on,
@@ -394,3 +402,39 @@ getnameinfo(const struct sockaddr *sa, int salen,
 
 	return 0;
 }
+
+/*
+ * Wrapper around gethostbyname() or gethostbyname_r() to mimic
+ * POSIX gethostbyname_r() behaviour, if it is not available or required.
+ */
+#ifdef FRONTEND
+static int
+pqGethostbyname(const char *name,
+				struct hostent *resultbuf,
+				char *buffer, size_t buflen,
+				struct hostent **result,
+				int *herrno)
+{
+#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R)
+
+	/*
+	 * broken (well early POSIX draft) gethostbyname_r() which returns 'struct
+	 * hostent *'
+	 */
+	*result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno);
+	return (*result == NULL) ? -1 : 0;
+#else
+
+	/* no gethostbyname_r(), just use gethostbyname() */
+	*result = gethostbyname(name);
+
+	if (*result != NULL)
+		*herrno = h_errno;
+
+	if (*result != NULL)
+		return 0;
+	else
+		return -1;
+#endif
+}
+#endif							/* FRONTEND */
diff --git a/src/port/path.c b/src/port/path.c
index 5ac26f4bcf..69bb8fe40b 100644
--- a/src/port/path.c
+++ b/src/port/path.c
@@ -815,16 +815,7 @@ get_home_path(char *ret_path)
 
 	home = getenv("HOME");
 	if (home == NULL || home[0] == '\0')
-	{
-		char		pwdbuf[BUFSIZ];
-		struct passwd pwdstr;
-		struct passwd *pwd = NULL;
-
-		(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
-		if (pwd == NULL)
-			return false;
-		home = pwd->pw_dir;
-	}
+		return pg_get_user_home_dir(geteuid(), ret_path, MAXPGPATH);
 	strlcpy(ret_path, home, MAXPGPATH);
 	return true;
 #else
diff --git a/src/port/thread.c b/src/port/thread.c
index c1040d4e24..23c3fbdf86 100644
--- a/src/port/thread.c
+++ b/src/port/thread.c
@@ -45,10 +45,9 @@
  *		use *_r function names if they exit
  *			(*_THREADSAFE=yes)
  *		use non-*_r functions if they are thread-safe
- *
- *	One thread-safe solution for gethostbyname() might be to use getaddrinfo().
  */
 
+#ifndef WIN32
 
 /*
  * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
@@ -60,8 +59,7 @@
  * error during lookup: returns an errno code, *result is NULL
  * (caller should *not* assume that the errno variable is set)
  */
-#ifndef WIN32
-int
+static int
 pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
 		   size_t buflen, struct passwd **result)
 {
@@ -75,42 +73,74 @@ pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
 	return (*result == NULL) ? errno : 0;
 #endif
 }
-#endif
 
 /*
- * Wrapper around gethostbyname() or gethostbyname_r() to mimic
- * POSIX gethostbyname_r() behaviour, if it is not available or required.
- * This function is called _only_ by our getaddrinfo() portability function.
+ * pg_get_user_name - get the name of the user with the given ID
+ *
+ * On success, the user name is returned into the buffer (of size buflen),
+ * and "true" is returned.  On failure, a localized error message is
+ * returned into the buffer, and "false" is returned.
  */
-#ifndef HAVE_GETADDRINFO
-int
-pqGethostbyname(const char *name,
-				struct hostent *resultbuf,
-				char *buffer, size_t buflen,
-				struct hostent **result,
-				int *herrno)
+bool
+pg_get_user_name(uid_t user_id, char *buffer, size_t buflen)
 {
-#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R)
+	char		pwdbuf[BUFSIZ];
+	struct passwd pwdstr;
+	struct passwd *pw = NULL;
+	int			pwerr;
 
-	/*
-	 * broken (well early POSIX draft) gethostbyname_r() which returns 'struct
-	 * hostent *'
-	 */
-	*result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno);
-	return (*result == NULL) ? -1 : 0;
-#else
-
-	/* no gethostbyname_r(), just use gethostbyname() */
-	*result = gethostbyname(name);
-
-	if (*result != NULL)
-		*herrno = h_errno;
-
-	if (*result != NULL)
-		return 0;
+	pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
+	if (pw != NULL)
+	{
+		strlcpy(buffer, pw->pw_name, buflen);
+		return true;
+	}
+	if (pwerr != 0)
+		snprintf(buffer, buflen,
+				 _("could not look up local user ID %d: %s"),
+				 (int) user_id,
+				 strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
 	else
-		return -1;
-#endif
+		snprintf(buffer, buflen,
+				 _("local user with ID %d does not exist"),
+				 (int) user_id);
+	return false;
 }
 
-#endif
+/*
+ * pg_get_user_home_dir - get the home directory of the user with the given ID
+ *
+ * On success, the directory path is returned into the buffer (of size buflen),
+ * and "true" is returned.  On failure, a localized error message is
+ * returned into the buffer, and "false" is returned.
+ *
+ * Note that this does not incorporate the common behavior of checking
+ * $HOME first, since it's independent of which user_id is queried.
+ */
+bool
+pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen)
+{
+	char		pwdbuf[BUFSIZ];
+	struct passwd pwdstr;
+	struct passwd *pw = NULL;
+	int			pwerr;
+
+	pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
+	if (pw != NULL)
+	{
+		strlcpy(buffer, pw->pw_dir, buflen);
+		return true;
+	}
+	if (pwerr != 0)
+		snprintf(buffer, buflen,
+				 _("could not look up local user ID %d: %s"),
+				 (int) user_id,
+				 strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
+	else
+		snprintf(buffer, buflen,
+				 _("local user with ID %d does not exist"),
+				 (int) user_id);
+	return false;
+}
+
+#endif							/* !WIN32 */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index deb62c1c7b..ec3546d0c0 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -106,7 +106,7 @@ sub mkvcbuild
 	  pread.c preadv.c pwrite.c pwritev.c pg_bitutils.c
 	  pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
 	  pqsignal.c mkdtemp.c qsort.c qsort_arg.c bsearch_arg.c quotes.c system.c
-	  strerror.c tar.c thread.c
+	  strerror.c tar.c
 	  win32env.c win32error.c win32ntdll.c
 	  win32security.c win32setlocale.c win32stat.c);