diff --git a/src/common/username.c b/src/common/username.c
index ee5ef1c072749d2fd1437b501352dc2cf314b1ac..686a6a43c51b8696a0b7c19e6280480c0c273d97 100644
--- a/src/common/username.c
+++ b/src/common/username.c
@@ -26,8 +26,8 @@
 #include "common/username.h"
 
 /*
- * Returns the current user name in a static buffer, or NULL on error and
- * sets errstr
+ * Returns the current user name in a static buffer
+ * On error, returns NULL and sets *errstr to point to a palloc'd message
  */
 const char *
 get_user_name(char **errstr)
@@ -50,15 +50,17 @@ get_user_name(char **errstr)
 
 	return pw->pw_name;
 #else
-	/* UNLEN = 256, 'static' variable remains after function exit */
+	/* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
+	/* "static" variable remains after function exit */
 	static char username[256 + 1];
-	DWORD		len = sizeof(username) - 1;
+	DWORD		len = sizeof(username);
 
 	*errstr = NULL;
 
 	if (!GetUserName(username, &len))
 	{
-		*errstr = psprintf(_("user name lookup failure: %s"), strerror(errno));
+		*errstr = psprintf(_("user name lookup failure: error code %lu"),
+						   GetLastError());
 		return NULL;
 	}
 
diff --git a/src/include/port.h b/src/include/port.h
index 1d53e4ec0b856ed353a958cf44d2e0c3fadcfc14..26d7fcd6721d60d2e5374ecf4563f110bba4a5ec 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -433,7 +433,7 @@ extern void srandom(unsigned int seed);
 /* thread.h */
 extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen);
 
-#if !defined(WIN32) || defined(__CYGWIN__)
+#ifndef WIN32
 extern int pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer,
 		   size_t buflen, struct passwd ** result);
 #endif
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 179793e2a0ef99547ed1814fbf1e16530058e6d6..8927df4f064a2d7fced76954c0c7207c91ae636b 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -714,22 +714,26 @@ pg_fe_sendauth(AuthRequest areq, PGconn *conn)
 /*
  * pg_fe_getauthname
  *
- * Returns a pointer to dynamic space containing whatever name the user
- * has authenticated to the system.  If there is an error, return NULL.
+ * 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 put a suitable error message in *errorMessage if that's not NULL.
  */
 char *
-pg_fe_getauthname(void)
+pg_fe_getauthname(PQExpBuffer errorMessage)
 {
+	char	   *result = NULL;
 	const char *name = NULL;
-	char	   *authn;
 
 #ifdef WIN32
-	char		username[128];
-	DWORD		namesize = sizeof(username) - 1;
+	/* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
+	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
 
 	/*
@@ -741,24 +745,42 @@ pg_fe_getauthname(void)
 	 */
 	pglock_thread();
 
-	/*
-	 * We document PQconndefaults() to return NULL for a memory allocation
-	 * failure.  We don't have an API to return a user name lookup failure, so
-	 * we just assume it always succeeds.
-	 */
 #ifdef WIN32
 	if (GetUserName(username, &namesize))
 		name = username;
+	else if (errorMessage)
+		printfPQExpBuffer(errorMessage,
+				 libpq_gettext("user name lookup failure: error code %lu\n"),
+						  GetLastError());
 #else
-	if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pw) == 0)
+	pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
+	if (pw != NULL)
 		name = pw->pw_name;
+	else if (errorMessage)
+	{
+		if (pwerr != 0)
+			printfPQExpBuffer(errorMessage,
+				   libpq_gettext("could not look up local user ID %d: %s\n"),
+							  (int) user_id,
+							  pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf)));
+		else
+			printfPQExpBuffer(errorMessage,
+					 libpq_gettext("local user with ID %d does not exist\n"),
+							  (int) user_id);
+	}
 #endif
 
-	authn = name ? strdup(name) : NULL;
+	if (name)
+	{
+		result = strdup(name);
+		if (result == NULL && errorMessage)
+			printfPQExpBuffer(errorMessage,
+							  libpq_gettext("out of memory\n"));
+	}
 
 	pgunlock_thread();
 
-	return authn;
+	return result;
 }
 
 
diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h
index 59b6c16a6d484e87461142a89e84259265a4798a..8d35767f7a0ca08f7cee0f2573168a1fa8571504 100644
--- a/src/interfaces/libpq/fe-auth.h
+++ b/src/interfaces/libpq/fe-auth.h
@@ -19,6 +19,6 @@
 
 
 extern int	pg_fe_sendauth(AuthRequest areq, PGconn *conn);
-extern char *pg_fe_getauthname(void);
+extern char *pg_fe_getauthname(PQExpBuffer errorMessage);
 
 #endif   /* FE_AUTH_H */
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index b2f556c1c301a0c39d7203f6ee1ba8781fb6708f..25961b1f10dc59b1aa86630068b8e1ab1be0d8ff 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -764,11 +764,27 @@ connectOptions1(PGconn *conn, const char *conninfo)
 static bool
 connectOptions2(PGconn *conn)
 {
+	/*
+	 * If user name was not given, fetch it.  (Most likely, the fetch will
+	 * fail, since the only way we get here is if pg_fe_getauthname() failed
+	 * during conninfo_add_defaults().  But now we want an error message.)
+	 */
+	if (conn->pguser == NULL || conn->pguser[0] == '\0')
+	{
+		if (conn->pguser)
+			free(conn->pguser);
+		conn->pguser = pg_fe_getauthname(&conn->errorMessage);
+		if (!conn->pguser)
+		{
+			conn->status = CONNECTION_BAD;
+			return false;
+		}
+	}
+
 	/*
 	 * If database name was not given, default it to equal user name
 	 */
-	if ((conn->dbName == NULL || conn->dbName[0] == '\0')
-		&& conn->pguser != NULL)
+	if (conn->dbName == NULL || conn->dbName[0] == '\0')
 	{
 		if (conn->dbName)
 			free(conn->dbName);
@@ -1967,6 +1983,7 @@ keep_going:						/* We will come back to here until there is
 					char		pwdbuf[BUFSIZ];
 					struct passwd pass_buf;
 					struct passwd *pass;
+					int			passerr;
 					uid_t		uid;
 					gid_t		gid;
 
@@ -1987,13 +2004,18 @@ keep_going:						/* We will come back to here until there is
 						goto error_return;
 					}
 
-					pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
-
+					passerr = pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
 					if (pass == NULL)
 					{
-						appendPQExpBuffer(&conn->errorMessage,
-										  libpq_gettext("local user with ID %d does not exist\n"),
-										  (int) uid);
+						if (passerr != 0)
+							appendPQExpBuffer(&conn->errorMessage,
+											  libpq_gettext("could not look up local user ID %d: %s\n"),
+											  (int) uid,
+											  pqStrerror(passerr, sebuf, sizeof(sebuf)));
+						else
+							appendPQExpBuffer(&conn->errorMessage,
+											  libpq_gettext("local user with ID %d does not exist\n"),
+											  (int) uid);
 						goto error_return;
 					}
 
@@ -4605,18 +4627,15 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage)
 		}
 
 		/*
-		 * Special handling for "user" option
+		 * Special handling for "user" option.  Note that if pg_fe_getauthname
+		 * fails, we just leave the value as NULL; there's no need for this to
+		 * be an error condition if the caller provides a user name.  The only
+		 * reason we do this now at all is so that callers of PQconndefaults
+		 * will see a correct default (barring error, of course).
 		 */
 		if (strcmp(option->keyword, "user") == 0)
 		{
-			option->val = pg_fe_getauthname();
-			if (!option->val)
-			{
-				if (errorMessage)
-					printfPQExpBuffer(errorMessage,
-									  libpq_gettext("out of memory\n"));
-				return false;
-			}
+			option->val = pg_fe_getauthname(NULL);
 			continue;
 		}
 	}
@@ -5843,7 +5862,8 @@ pqGetHomeDirectory(char *buf, int bufsize)
 	struct passwd pwdstr;
 	struct passwd *pwd = NULL;
 
-	if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
+	(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
+	if (pwd == NULL)
 		return false;
 	strlcpy(buf, pwd->pw_dir, bufsize);
 	return true;
diff --git a/src/port/path.c b/src/port/path.c
index e8faac3a2607f41b533008940dc811112a5e90d1..d0f72df29c2fd9d8f669ee369ffbefc11083c034 100644
--- a/src/port/path.c
+++ b/src/port/path.c
@@ -777,7 +777,8 @@ get_home_path(char *ret_path)
 	struct passwd pwdstr;
 	struct passwd *pwd = NULL;
 
-	if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
+	(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
+	if (pwd == NULL)
 		return false;
 	strlcpy(ret_path, pwd->pw_dir, MAXPGPATH);
 	return true;
diff --git a/src/port/thread.c b/src/port/thread.c
index 1568803d6264671351aa26f393cd4c0639f7acd1..aab74516ac9626d2f0ecee0473e4b9dd412e7918 100644
--- a/src/port/thread.c
+++ b/src/port/thread.c
@@ -83,6 +83,12 @@ pqStrerror(int errnum, char *strerrbuf, size_t buflen)
 /*
  * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
  * behaviour, if it is not available or required.
+ *
+ * Per POSIX, the possible cases are:
+ * success: returns zero, *result is non-NULL
+ * uid not found: returns zero, *result is NULL
+ * error during lookup: returns an errno code, *result is NULL
+ * (caller should *not* assume that the errno variable is set)
  */
 #ifndef WIN32
 int
@@ -93,22 +99,25 @@ pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer,
 
 #ifdef GETPWUID_R_5ARG
 	/* POSIX version */
-	getpwuid_r(uid, resultbuf, buffer, buflen, result);
+	return getpwuid_r(uid, resultbuf, buffer, buflen, result);
 #else
 
 	/*
 	 * Early POSIX draft of getpwuid_r() returns 'struct passwd *'.
 	 * getpwuid_r(uid, resultbuf, buffer, buflen)
 	 */
+	errno = 0;
 	*result = getpwuid_r(uid, resultbuf, buffer, buflen);
+	/* paranoia: ensure we return zero on success */
+	return (*result == NULL) ? errno : 0;
 #endif
 #else
-
 	/* no getpwuid_r() available, just use getpwuid() */
+	errno = 0;
 	*result = getpwuid(uid);
+	/* paranoia: ensure we return zero on success */
+	return (*result == NULL) ? errno : 0;
 #endif
-
-	return (*result == NULL) ? -1 : 0;
 }
 #endif