diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 746d7cbb8a..82510fda63 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -206,6 +206,12 @@ static int pg_SSPI_make_upn(char *accountname,
 static int	CheckRADIUSAuth(Port *port);
 static int	PerformRadiusTransaction(const char *server, const char *secret, const char *portstr, const char *identifier, const char *user_name, const char *passwd);
 
+/*----------------------------------------------------------------
+ * Connection Redirection
+ *----------------------------------------------------------------
+ */
+static int SendAlternativeServerName(Port *port, char **logdetail);
+
 
 /*
  * Maximum accepted size of GSS and SSPI authentication tokens.
@@ -598,6 +604,9 @@ ClientAuthentication(Port *port)
 		case uaTrust:
 			status = STATUS_OK;
 			break;
+		case uaRedirect:
+			status = SendAlternativeServerName(port, &logdetail);
+			break;
 	}
 
 	if (ClientAuthentication_hook)
@@ -609,6 +618,28 @@ ClientAuthentication(Port *port)
 		auth_failed(port, status, logdetail);
 }
 
+/*
+ * Send alternative server information packet to the frontend.
+ */
+static int
+SendAlternativeServerName(Port *port, char **logdetail)
+{
+	StringInfoData buf;
+
+	CHECK_FOR_INTERRUPTS();
+
+	pq_beginmessage(&buf, 'M');
+	pq_sendstring(&buf, "server");
+	pq_sendstring(&buf, port->hba->alternativeservername);
+	pq_sendstring(&buf, "port");
+	pq_sendstring(&buf, port->hba->alternativeserverport);
+
+	pq_endmessage(&buf);
+	pq_flush();
+	proc_exit(0);
+
+	return STATUS_OK;
+}
 
 /*
  * Send an authentication request packet to the frontend.
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index aa20f266b8..d211068f44 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -134,7 +134,8 @@ static const char *const UserAuthName[] =
 	"ldap",
 	"cert",
 	"radius",
-	"peer"
+	"peer",
+	"redirect"
 };
 
 
@@ -1358,6 +1359,8 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
 #endif
 	else if (strcmp(token->string, "radius") == 0)
 		parsedline->auth_method = uaRADIUS;
+	else if (strcmp(token->string, "redirect") == 0)
+		parsedline->auth_method = uaRedirect;
 	else
 	{
 		ereport(elevel,
@@ -1384,6 +1387,49 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
 		return NULL;
 	}
 
+	if (parsedline->auth_method == uaRedirect)
+	{
+		/* Get the alternative server name and port */
+		field = lnext(field);
+		if (!field)
+		{
+			ereport(elevel,
+				(errcode(ERRCODE_CONFIG_FILE_ERROR),
+				errmsg("end-of-line before alternative server name"),
+				errcontext("line %d of configuration file \"%s\"",
+				line_num, HbaFileName)));
+			*err_msg = "end-of-line before alternative server name";
+			return NULL;
+		}
+		tokens = lfirst(field);
+		if (tokens->length > 2)
+		{
+			ereport(elevel,
+				(errcode(ERRCODE_CONFIG_FILE_ERROR),
+				errmsg("multiple values specified for alternative server"),
+				errhint("Specify exactly one alternative server per line."),
+				errcontext("line %d of configuration file \"%s\"",
+				line_num, HbaFileName)));
+			*err_msg = "multiple values specified for alternative server";
+			return NULL;
+		}
+
+		tokencell = list_head(tokens);
+		token = lfirst(tokencell);
+		parsedline->alternativeservername = pstrdup(token->string);
+
+		if (tokens->length == 2)
+		{
+			tokencell = lnext(tokencell);
+			token = lfirst(tokencell);
+			parsedline->alternativeserverport = pstrdup(token->string);
+		}
+		else
+		{
+			pg_itoa(DEF_PGPORT, parsedline->alternativeserverport);
+		}
+	}
+
 	/*
 	 * XXX: When using ident on local connections, change it to peer, for
 	 * backwards compatibility.
@@ -2100,6 +2146,12 @@ check_hba(hbaPort *port)
 		if (!check_role(port->user_name, roleid, hba->roles))
 			continue;
 
+		/* Check the protocol version to see if the client supports redirection */
+		if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
+			(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
+			 PG_PROTOCOL_MINOR(port->proto) < PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
+			continue;
+
 		/* Found a record that matched! */
 		port->hba = hba;
 		return;
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index c853e36232..3af0972d48 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -43,7 +43,7 @@
 # directly connected to.
 #
 # METHOD can be "trust", "reject", "md5", "password", "scram-sha-256",
-# "gss", "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert".
+# "gss", "sspi", "ident", "peer", "pam", "ldap", "radius", "cert" or "redirect".
 # Note that "password" sends passwords in clear text; "md5" or
 # "scram-sha-256" are preferred since they send encrypted passwords.
 #
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 5f68f4c666..1e4f2bd6db 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -38,8 +38,9 @@ typedef enum UserAuth
 	uaLDAP,
 	uaCert,
 	uaRADIUS,
-	uaPeer
-#define USER_AUTH_LAST uaPeer	/* Must be last value of this enum */
+	uaPeer,
+	uaRedirect
+#define USER_AUTH_LAST uaRedirect	/* Must be last value of this enum */
 } UserAuth;
 
 typedef enum IPCompareMethod
@@ -99,6 +100,8 @@ typedef struct HbaLine
 	char	   *radiusidentifiers_s;
 	List	   *radiusports;
 	char	   *radiusports_s;
+	char	   *alternativeservername;
+	char	   *alternativeserverport;
 } HbaLine;
 
 typedef struct IdentLine
