diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 62a3b21..e79f96c 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -232,6 +232,12 @@ EOF
       with a slash, it is used as the directory for the Unix-domain
       socket.
       </para>
+      <para>
+      It is possible to provide multiple host names to connect to. The first host name that accepts
+      the connection will be used. To explicitly specify multiple host names they must be separated
+      by comma.
+      An alternative is to use dns record for the host name that resolves to multiple addresses.
+      </para>
       </listitem>
     </varlistentry>
 
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
index db939b5..90d3c1e 100644
--- a/src/backend/libpq/ip.c
+++ b/src/backend/libpq/ip.c
@@ -56,6 +56,9 @@ static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
 				 int flags);
 #endif
 
+/* Marker for multiple dns resolver results linked together */
+#define AI_PG_LINKED	(1<<30)
+
 
 /*
  *	pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
@@ -65,6 +68,9 @@ pg_getaddrinfo_all(const char *hostname, const char *servname,
 				   const struct addrinfo * hintp, struct addrinfo ** result)
 {
 	int			rc;
+	char			*hostnames;
+	char			*host_start;
+	struct addrinfo	*addr;
 
 	/* not all versions of getaddrinfo() zero *result on failure */
 	*result = NULL;
@@ -73,10 +79,46 @@ pg_getaddrinfo_all(const char *hostname, const char *servname,
 	if (hintp->ai_family == AF_UNIX)
 		return getaddrinfo_unix(servname, hintp, result);
 #endif
-
 	/* NULL has special meaning to getaddrinfo(). */
-	rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
-					 servname, hintp, result);
+	if (!hostname || hostname[0] == '\0')
+		return getaddrinfo(NULL, servname, hintp, result);
+
+	hostnames = strdup(hostname);
+	if (!hostnames)
+		return EAI_MEMORY;
+
+	host_start = hostnames;
+
+	/* dns lookups in reverse order to make result links in correct order */
+	do
+	{
+		host_start = strrchr(hostnames, ',');
+		if (host_start)
+		{
+			*host_start = '\0';
+			host_start++;
+		}
+		else
+			host_start = hostnames;
+
+		addr = NULL;
+		rc = getaddrinfo(host_start, servname, hintp, &addr);
+		if (rc || !addr)
+		{
+			if (addr)
+				freeaddrinfo(addr);
+			break;
+		}
+		if (*result)
+		{
+			(*result)->ai_flags |= AI_PG_LINKED;
+			addr->ai_next = *result;
+		}
+		*result = addr;
+
+	} while (host_start > hostnames);
+
+	free(hostnames);
 
 	return rc;
 }
@@ -94,6 +136,9 @@ pg_getaddrinfo_all(const char *hostname, const char *servname,
 void
 pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
 {
+	struct addrinfo * last_addrinfo;
+	struct addrinfo * ai_ptr;
+
 #ifdef HAVE_UNIX_SOCKETS
 	if (hint_ai_family == AF_UNIX)
 	{
@@ -109,10 +154,24 @@ pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
 	}
 	else
 #endif   /* HAVE_UNIX_SOCKETS */
+	/* struct was built by getaddrinfo() */
+	if (ai != NULL)
 	{
-		/* struct was built by getaddrinfo() */
-		if (ai != NULL)
-			freeaddrinfo(ai);
+		while (true)
+		{
+			/* unlink extra addrinfo structures before freeing */
+			last_addrinfo = NULL;
+			for (ai_ptr = ai; ai_ptr->ai_next; ai_ptr = ai_ptr->ai_next)
+			{
+				if (ai_ptr->ai_next->ai_flags & AI_PG_LINKED)
+					last_addrinfo = ai_ptr;
+			}
+			if (!last_addrinfo)
+				break;
+			freeaddrinfo(last_addrinfo->ai_next);
+			last_addrinfo->ai_next = NULL;
+		}
+		freeaddrinfo(ai);
 	}
 }
 
