diff --git a/contrib/pg_upgrade/util.c b/contrib/pg_upgrade/util.c
index a67bd64043f1344f760f8d397f91800d2873412e..c3d45237fde6337c7f0eae4b7f45478489a3c0d3 100644
--- a/contrib/pg_upgrade/util.c
+++ b/contrib/pg_upgrade/util.c
@@ -203,32 +203,25 @@ quote_identifier(const char *s)
 
 /*
  * get_user_info()
- * (copied from initdb.c) find the current user
  */
 int
 get_user_info(char **user_name)
 {
 	int			user_id;
+	char	   *errstr;
 
 #ifndef WIN32
-	struct passwd *pw = getpwuid(geteuid());
-
 	user_id = geteuid();
-#else							/* the windows code */
-	struct passwd_win32
-	{
-		int			pw_uid;
-		char		pw_name[128];
-	}			pass_win32;
-	struct passwd_win32 *pw = &pass_win32;
-	DWORD		pwname_size = sizeof(pass_win32.pw_name) - 1;
-
-	GetUserName(pw->pw_name, &pwname_size);
-
+#else
 	user_id = 1;
 #endif
 
-	*user_name = pg_strdup(pw->pw_name);
+	*user_name = get_user_name(&errstr);
+	if (!*user_name)
+		pg_fatal("%s\n", errstr);
+
+	/* make a copy */
+	*user_name = pg_strdup(*user_name);
 
 	return user_id;
 }
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 2dbf7e53a1294ec2a5f7c16bbc899bf5472b53ba..6d11e576a4bf504da6158118a45e637e4d974154 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -1771,7 +1771,8 @@ auth_peer(hbaPort *port)
 	char		ident_user[IDENT_USERNAME_MAX + 1];
 	uid_t		uid;
 	gid_t		gid;
-	struct passwd *pass;
+	const char *user_name;
+	char	   *errstr;
 
 	errno = 0;
 	if (getpeereid(port->sock, &uid, &gid) != 0)
@@ -1788,17 +1789,15 @@ auth_peer(hbaPort *port)
 		return STATUS_ERROR;
 	}
 
-	pass = getpwuid(uid);
-
-	if (pass == NULL)
+	user_name = get_user_name(&errstr);
+	if (!user_name)
 	{
-		ereport(LOG,
-				(errmsg("local user with ID %d does not exist",
-						(int) uid)));
+		ereport(LOG, (errmsg_internal("%s", errstr)));
+		pfree(errstr);
 		return STATUS_ERROR;
 	}
 
-	strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
+	strlcpy(ident_user, user_name, IDENT_USERNAME_MAX + 1);
 
 	return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
 }
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index d71885dba9d50f8ad0533f2697db48047851ea20..376aa39a98565b9a026217b062c460af32022fea 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -20,7 +20,6 @@
  */
 #include "postgres.h"
 
-#include <pwd.h>
 #include <unistd.h>
 
 #if defined(__alpha) && defined(__osf__)		/* no __alpha__ ? */
@@ -49,7 +48,6 @@ const char *progname;
 static void startup_hacks(const char *progname);
 static void help(const char *progname);
 static void check_root(const char *progname);
-static char *get_current_username(const char *progname);
 
 
 /*
@@ -191,7 +189,7 @@ main(int argc, char *argv[])
 	else if (argc > 1 && strcmp(argv[1], "--single") == 0)
 		PostgresMain(argc, argv,
 					 NULL,		/* no dbname */
-					 get_current_username(progname));	/* does not return */
+					 strdup(get_user_name_or_exit(progname)));	/* does not return */
 	else
 		PostmasterMain(argc, argv);		/* does not return */
 	abort();					/* should not get here */
@@ -372,36 +370,3 @@ check_root(const char *progname)
 	}
 #endif   /* WIN32 */
 }
-
-
-
-static char *
-get_current_username(const char *progname)
-{
-#ifndef WIN32
-	struct passwd *pw;
-
-	pw = getpwuid(geteuid());
-	if (pw == NULL)
-	{
-		write_stderr("%s: invalid effective UID: %d\n",
-					 progname, (int) geteuid());
-		exit(1);
-	}
-	/* Allocate new memory because later getpwuid() calls can overwrite it. */
-	return strdup(pw->pw_name);
-#else
-	unsigned long namesize = 256 /* UNLEN */ + 1;
-	char	   *name;
-
-	name = malloc(namesize);
-	if (!GetUserName(name, &namesize))
-	{
-		write_stderr("%s: could not determine user name (GetUserName failed)\n",
-					 progname);
-		exit(1);
-	}
-
-	return name;
-#endif
-}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index e6bb132beaf69d38967f0fc9c94319d03a4ae755..964d284bb661e7b88a4f0688f66a6128ab13fe1d 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -770,15 +770,14 @@ exit_nicely(void)
 /*
  * find the current user
  *
- * on unix make sure it isn't really root
+ * on unix make sure it isn't root
  */
 static char *
 get_id(void)
 {
-#ifndef WIN32
-
-	struct passwd *pw;
+	const char	   *username;
 
+#ifndef WIN32
 	if (geteuid() == 0)			/* 0 is root's uid */
 	{
 		fprintf(stderr,
@@ -789,35 +788,11 @@ get_id(void)
 				progname);
 		exit(1);
 	}
-
-	pw = getpwuid(geteuid());
-	if (!pw)
-	{
-		fprintf(stderr,
-			  _("%s: could not obtain information about current user: %s\n"),
-				progname, strerror(errno));
-		exit(1);
-	}
-#else							/* the windows code */
-
-	struct passwd_win32
-	{
-		int			pw_uid;
-		char		pw_name[128];
-	}			pass_win32;
-	struct passwd_win32 *pw = &pass_win32;
-	DWORD		pwname_size = sizeof(pass_win32.pw_name) - 1;
-
-	pw->pw_uid = 1;
-	if (!GetUserName(pw->pw_name, &pwname_size))
-	{
-		fprintf(stderr, _("%s: could not get current user name: %s\n"),
-				progname, strerror(errno));
-		exit(1);
-	}
 #endif
 
-	return pg_strdup(pw->pw_name);
+	username = get_user_name_or_exit(progname);
+
+	return pg_strdup(username);
 }
 
 static char *
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 638d8cb5c31977699c40a5c95b3f067cba8e1d5b..d60a661543dac1d1b79e8fd18e13397d655eb89d 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -265,10 +265,13 @@ exec_command(const char *cmd,
 #ifndef WIN32
 			struct passwd *pw;
 
+			errno = 0;	/* clear errno before call */
 			pw = getpwuid(geteuid());
 			if (!pw)
 			{
-				psql_error("could not get home directory: %s\n", strerror(errno));
+				psql_error("could not get home directory for user id %d: %s\n",
+						   (int) geteuid(), errno ?
+						   strerror(errno) : "user does not exist");
 				exit(EXIT_FAILURE);
 			}
 			dir = pw->pw_dir;
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 30530f2e37cb8c3beba2eab8746483d29cae56dd..80b1ec0dfc795c08daebdc61a8d3a3d36a7f6264 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -8,9 +8,6 @@
 #include "postgres_fe.h"
 
 #ifndef WIN32
-#ifdef HAVE_PWD_H
-#include <pwd.h>				/* for getpwuid() */
-#endif
 #include <sys/types.h>			/* (ditto) */
 #include <unistd.h>				/* for geteuid() */
 #else
@@ -52,31 +49,18 @@ usage(void)
 {
 	const char *env;
 	const char *user;
-
-#ifndef WIN32
-	struct passwd *pw = NULL;
-#endif
+	char	   *errstr;
 
 	/* Find default user, in case we need it. */
 	user = getenv("PGUSER");
 	if (!user)
 	{
-#if !defined(WIN32) && !defined(__OS2__)
-		pw = getpwuid(geteuid());
-		if (pw)
-			user = pw->pw_name;
-		else
+		user = get_user_name(&errstr);
+		if (!user)
 		{
-			psql_error("could not get current user name: %s\n", strerror(errno));
+			psql_error("%s\n", errstr);
 			exit(EXIT_FAILURE);
 		}
-#else							/* WIN32 */
-		char		buf[128];
-		DWORD		bufsize = sizeof(buf) - 1;
-
-		if (GetUserName(buf, &bufsize))
-			user = buf;
-#endif   /* WIN32 */
 	}
 
 	printf(_("psql is the PostgreSQL interactive terminal.\n\n"));
diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c
index cd54e8f47f77868b0756d78f1843278d3cc53d73..e7065ce5df985dc8900e6032cd4d29b7256d29c9 100644
--- a/src/bin/scripts/clusterdb.c
+++ b/src/bin/scripts/clusterdb.c
@@ -160,7 +160,7 @@ main(int argc, char *argv[])
 			else if (getenv("PGUSER"))
 				dbname = getenv("PGUSER");
 			else
-				dbname = get_user_name(progname);
+				dbname = get_user_name_or_exit(progname);
 		}
 
 		if (tables.head != NULL)
diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c
index 4645bc137f94aebb9d089e66fd7960aa1300d283..e57e5207c6bffc47fe79d5102babaf7d388c20c6 100644
--- a/src/bin/scripts/common.c
+++ b/src/bin/scripts/common.c
@@ -14,7 +14,6 @@
 
 #include "postgres_fe.h"
 
-#include <pwd.h>
 #include <signal.h>
 #include <unistd.h>
 
@@ -29,38 +28,6 @@ static PGcancel *volatile cancelConn = NULL;
 static CRITICAL_SECTION cancelConnLock;
 #endif
 
-/*
- * Returns the current user name.
- */
-const char *
-get_user_name(const char *progname)
-{
-#ifndef WIN32
-	struct passwd *pw;
-
-	pw = getpwuid(geteuid());
-	if (!pw)
-	{
-		fprintf(stderr, _("%s: could not obtain information about current user: %s\n"),
-				progname, strerror(errno));
-		exit(1);
-	}
-	return pw->pw_name;
-#else
-	static char username[128];	/* remains after function exit */
-	DWORD		len = sizeof(username) - 1;
-
-	if (!GetUserName(username, &len))
-	{
-		fprintf(stderr, _("%s: could not get current user name: %s\n"),
-				progname, strerror(errno));
-		exit(1);
-	}
-	return username;
-#endif
-}
-
-
 /*
  * Provide strictly harmonized handling of --help and --version
  * options.
diff --git a/src/bin/scripts/common.h b/src/bin/scripts/common.h
index 6cf490f7484588269aea2fca6be614c6de1376ac..a8a81f66b4b80d190721068583da1a597b059728 100644
--- a/src/bin/scripts/common.h
+++ b/src/bin/scripts/common.h
@@ -22,8 +22,6 @@ enum trivalue
 
 typedef void (*help_handler) (const char *progname);
 
-extern const char *get_user_name(const char *progname);
-
 extern void handle_help_version_opts(int argc, char *argv[],
 						 const char *fixed_progname,
 						 help_handler hlp);
diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c
index 14cd128490652f48977344f3a203e36a80dc8a5d..856a04d6485bff4196ca8b8cfbd58885f341894e 100644
--- a/src/bin/scripts/createdb.c
+++ b/src/bin/scripts/createdb.c
@@ -174,7 +174,7 @@ main(int argc, char *argv[])
 		else if (getenv("PGUSER"))
 			dbname = getenv("PGUSER");
 		else
-			dbname = get_user_name(progname);
+			dbname = get_user_name_or_exit(progname);
 	}
 
 	initPQExpBuffer(&sql);
diff --git a/src/bin/scripts/createlang.c b/src/bin/scripts/createlang.c
index ff544a803d1335705814e7fba869c81b8ad30ae8..5cfba8e3d5a679dda4261aa00e4ac7191759e73b 100644
--- a/src/bin/scripts/createlang.c
+++ b/src/bin/scripts/createlang.c
@@ -127,7 +127,7 @@ main(int argc, char *argv[])
 		else if (getenv("PGUSER"))
 			dbname = getenv("PGUSER");
 		else
-			dbname = get_user_name(progname);
+			dbname = get_user_name_or_exit(progname);
 	}
 
 	initPQExpBuffer(&sql);
diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c
index 61805917704a0e34fdf137483ff8f4a81ca58ab3..e3ce0dc455f64b8f61741f285045713e225ef542 100644
--- a/src/bin/scripts/createuser.c
+++ b/src/bin/scripts/createuser.c
@@ -193,7 +193,7 @@ main(int argc, char *argv[])
 			if (getenv("PGUSER"))
 				newuser = getenv("PGUSER");
 			else
-				newuser = get_user_name(progname);
+				newuser = get_user_name_or_exit(progname);
 		}
 	}
 
diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c
index de20317343878f3b18b9f82dece0fa2385c1e580..b9664a918500015f75e78284536f46192444ca6c 100644
--- a/src/bin/scripts/droplang.c
+++ b/src/bin/scripts/droplang.c
@@ -126,7 +126,7 @@ main(int argc, char *argv[])
 		else if (getenv("PGUSER"))
 			dbname = getenv("PGUSER");
 		else
-			dbname = get_user_name(progname);
+			dbname = get_user_name_or_exit(progname);
 	}
 
 	initPQExpBuffer(&sql);
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index f7c09bebf8a4789b86dc8dbc891a0b3ae2c6e6e7..4e762ea56f4e62107eba26024553fc682a4dbc99 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -188,7 +188,7 @@ main(int argc, char *argv[])
 			else if (getenv("PGUSER"))
 				dbname = getenv("PGUSER");
 			else
-				dbname = get_user_name(progname);
+				dbname = get_user_name_or_exit(progname);
 		}
 
 		reindex_system_catalogs(dbname, host, port, username, prompt_password,
@@ -203,7 +203,7 @@ main(int argc, char *argv[])
 			else if (getenv("PGUSER"))
 				dbname = getenv("PGUSER");
 			else
-				dbname = get_user_name(progname);
+				dbname = get_user_name_or_exit(progname);
 		}
 
 		if (indexes.head != NULL)
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index 616d9339e1ed6ed8e71fb02786757185b5cd3b13..8970ec6ad2e7240e36cd617391fcfdd1d5ae43dd 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -202,7 +202,7 @@ main(int argc, char *argv[])
 			else if (getenv("PGUSER"))
 				dbname = getenv("PGUSER");
 			else
-				dbname = get_user_name(progname);
+				dbname = get_user_name_or_exit(progname);
 		}
 
 		if (tables.head != NULL)
diff --git a/src/include/port.h b/src/include/port.h
index 5ef4b0a0b11863d96213e4379ee958109691cb98..473c4f6a7b28445ad8e828fb4135b69b3128c4e5 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -473,6 +473,10 @@ extern pqsigfunc pqsignal(int signo, pqsigfunc func);
 /* port/quotes.c */
 extern char *escape_single_quotes_ascii(const char *src);
 
+/* port/username.c */
+extern const char *get_user_name(char **errstr);
+extern const char *get_user_name_or_exit(const char *progname);
+
 /* port/wait_error.c */
 extern char *wait_result_to_str(int exit_status);
 
diff --git a/src/port/Makefile b/src/port/Makefile
index 1be4ff57a2f5fc46dba49c247dbd68532388cfe2..a50e0af2143c39e5f83815e5b3aa30e680be8f00 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -33,7 +33,7 @@ LIBS += $(PTHREAD_LIBS)
 OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o fls.o inet_net_ntop.o \
 	noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \
 	pgstrcasecmp.o pqsignal.o \
-	qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
+	qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o username.o
 
 # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
 OBJS_SRV = $(OBJS:%.o=%_srv.o)
diff --git a/src/port/username.c b/src/port/username.c
new file mode 100644
index 0000000000000000000000000000000000000000..25dc9391c4432a11b66ae8bc0d3d41fbae68fcd4
--- /dev/null
+++ b/src/port/username.c
@@ -0,0 +1,84 @@
+/*-------------------------------------------------------------------------
+ *
+ * username.c
+ *	  get user name
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/port/username.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <errno.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+/*
+ * Returns the current user name in a static buffer, or NULL on error and
+ * sets errstr
+ */
+const char *
+get_user_name(char **errstr)
+{
+#ifndef WIN32
+	struct passwd *pw;
+	uid_t user_id = geteuid();
+
+	*errstr = NULL;
+
+	errno = 0;	/* clear errno before call */
+	pw = getpwuid(user_id);
+	if (!pw)
+	{
+		*errstr = psprintf(_("failed to look up effective user id %d: %s"),
+				(int) user_id, errno ? strerror(errno) :
+				_("user does not exist"));
+		return NULL;
+	}
+
+	return pw->pw_name;
+#else
+	/* UNLEN = 256, 'static' variable remains after function exit */
+	static char username[256 + 1]; 
+	DWORD		len = sizeof(username) - 1;
+
+	if (!GetUserName(username, &len))
+	{
+		*errstr = psprintf(_("user name lookup failure: %s"), strerror(errno));
+		return NULL;
+	}
+
+	return username;
+#endif
+}
+
+
+/*
+ * Returns the current user name in a static buffer or exits
+ */
+const char *
+get_user_name_or_exit(const char *progname)
+{
+	const char *user_name;
+	char 	   *errstr;
+
+	user_name = get_user_name(&errstr);
+
+	if (!user_name)
+	{
+		fprintf(stderr, "%s: %s\n", progname, errstr);
+		exit(1);
+	}
+	return user_name;
+}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index bc7f4496e01e90345f241fe49f776a86e213adf9..d6b6eaf158438e48c407b8461ff2835d02717652 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -70,8 +70,8 @@ sub mkvcbuild
 	  erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
 	  pgcheckdir.c pg_crc.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
 	  qsort.c qsort_arg.c quotes.c
-	  sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c rint.c win32env.c
-	  win32error.c win32setlocale.c);
+	  sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c rint.c username.c
+	  win32env.c win32error.c win32setlocale.c);
 
 	our @pgcommonallfiles = qw(
 	  exec.c pgfnames.c psprintf.c relpath.c rmtree.c wait_error.c);