diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 53832d08e2..a98b2d0fcd 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -495,6 +495,18 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
        </varlistentry>
 
        <varlistentry>
+        <term><literal>redirect</></term>
+        <listitem>
+         <para>
+          Redirects the connection to the alternative server specified if it
+          matches the requested database user name and IP address. This is
+          only available for Protocol Version 3.1 and beyond.
+          See <xref linkend="auth-redirect"> for details.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
         <term><literal>ldap</literal></term>
         <listitem>
          <para>
@@ -624,7 +636,7 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
    non-null <structfield>error</structfield> fields indicate problems in the
    corresponding lines of the file.
   </para>
- 
+
   <tip>
    <para>
     To connect to a particular database, a user must not only pass the
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d543334ae..529226c043 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1809,7 +1809,7 @@ connectDBStart(PGconn *conn)
 	 */
 	conn->whichhost = 0;
 	conn->addr_cur = conn->connhost[0].addrlist;
-	conn->pversion = PG_PROTOCOL(3, 0);
+	conn->pversion = PG_PROTOCOL(3, 1);
 	conn->send_appname = true;
 	conn->status = CONNECTION_NEEDED;
 
@@ -2007,6 +2007,14 @@ PQconnectPoll(PGconn *conn)
 	int			optval;
 	PQExpBufferData savedMessage;
 
+	/* Variable declarations for redirection. */
+	int			originalMsgLen;		/* Length in bytes of message sans msg type */
+	int			runningMsgLen;		/* Length in bytes of message sans metadata */
+	int			availableMsgLen;
+	char		*altServer = NULL;
+	char		*altPort = NULL;
+	bool		redirectionError = false; /* Flag used to mark exceptions */
+
 	if (conn == NULL)
 		return PGRES_POLLING_FAILED;
 
@@ -2024,6 +2032,7 @@ PQconnectPoll(PGconn *conn)
 
 			/* These are reading states */
 		case CONNECTION_AWAITING_RESPONSE:
+		case CONNECTION_REDIRECTION:
 		case CONNECTION_AUTH_OK:
 			{
 				/* Load waiting data */
@@ -2655,6 +2664,12 @@ keep_going:						/* We will come back to here until there is
 					return PGRES_POLLING_READING;
 				}
 
+				if (beresp == 'M')
+				{
+					conn->status = CONNECTION_REDIRECTION;
+					goto keep_going;
+				}
+
 				/*
 				 * Validate message type: we expect only an authentication
 				 * request or an error here.  Anything else probably means
@@ -3097,6 +3112,125 @@ keep_going:						/* We will come back to here until there is
 				conn->status = CONNECTION_OK;
 				return PGRES_POLLING_OK;
 			}
+
+		case CONNECTION_REDIRECTION:
+			{
+				/* Mark 'M' consumed: a single byte for message type. */
+				conn->inCursor = conn->inStart + 1;
+
+				/* Obtain message length from packet. */
+				if (pqGetInt(&originalMsgLen, sizeof(int32), conn))
+					return PGRES_POLLING_READING;
+
+				/* Obtain the number of bytes in payload. */
+				runningMsgLen = originalMsgLen - sizeof(int32);
+
+				/* Enlarge buffer if payload's size is greater than what is available. */
+				availableMsgLen = conn->inEnd - conn->inCursor;
+				if (availableMsgLen < runningMsgLen)
+				{
+					if (pqCheckInBufferSpace(conn->inCursor + (size_t)runningMsgLen, conn))
+						return PGRES_POLLING_READING;
+				}
+
+				PQExpBuffer buf = createPQExpBuffer();
+				while (pqGets(buf, conn) != EOF)
+				{
+					if (!strcmp(buf->data, "server"))
+					{
+						if (pqGets(buf, conn) == EOF)
+						{
+							appendPQExpBuffer(&conn->errorMessage,
+								libpq_gettext("failed to obtain server value from redirection packet"));
+
+							redirectionError = true;
+							break;
+						}
+						altServer = strdup(buf->data);
+					}
+					else if (!strcmp(buf->data, "port"))
+					{
+						if (pqGets(buf, conn) == EOF)
+						{
+							appendPQExpBuffer(&conn->errorMessage,
+								libpq_gettext("failed to obtain port value from redirection packet"));
+
+							redirectionError = true;
+							break;
+						}
+						altPort = strdup(buf->data);
+					}
+					else
+					{
+						appendPQExpBuffer(&conn->errorMessage,
+							libpq_gettext("unknown key in redirection server packet"));
+						redirectionError = true;
+					}
+
+					if (redirectionError)
+					{
+						/* Free buffer to prevent memory leak on error. */
+						destroyPQExpBuffer(buf);
+
+						/* Free strdup'd variables. */
+						if (altServer)
+							free(altServer);
+
+						if (altPort)
+							free(altPort);
+
+						goto error_return;
+					}
+
+					/* Buffer length does not account for null-terminated strings. */
+					runningMsgLen -= buf->len + 1;
+				}
+
+				/* Free buffer used for reading string params in packet. */
+				destroyPQExpBuffer(buf);
+
+				/* Check for extraneous data in packet. */
+				if (conn->inCursor != conn->inStart + 1 + originalMsgLen)
+				{
+					appendPQExpBuffer(&conn->errorMessage,
+						libpq_gettext("Extraneous data in redirection packet from server\n"));
+
+					/* Free strdup'd variables. */
+					if (altServer)
+						free(altServer);
+
+					if (altPort)
+						free(altPort);
+
+					goto error_return;
+				}
+
+				/* Mark incoming data consumed */
+				conn->inStart = conn->inCursor;
+
+				/* Drop existing connection. */
+				pqDropConnection(conn, true);
+
+				/* Set connection parameters. */
+				if (conn->pghost)
+				{
+					free(conn->pghost);
+					conn->pghost = altServer;
+				}
+
+				if (conn->pgport)
+				{
+					free(conn->pgport);
+					conn->pgport = altPort;
+				}
+
+				/* connectDBStart() sets appropriate connection status. */
+				if (!connectOptions2(conn) || !connectDBStart(conn))
+					conn->status = CONNECTION_BAD;
+
+				goto keep_going;
+			}
+
 		case CONNECTION_CHECK_WRITABLE:
 			{
 				const char *displayed_host;
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ed9c806861..2a8f036b4b 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -65,8 +65,9 @@ typedef enum
 	CONNECTION_NEEDED,			/* Internal state: connect() needed */
 	CONNECTION_CHECK_WRITABLE,	/* Check if we could make a writable
 								 * connection. */
-	CONNECTION_CONSUME			/* Wait for any pending message and consume
+	CONNECTION_CONSUME,			/* Wait for any pending message and consume
 								 * them. */
+	CONNECTION_REDIRECTION		/* Redirection */
 } ConnStatusType;
 
 typedef enum
