diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 4930506..d041a02 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7555,6 +7555,11 @@
      </row>
 
      <row>
+      <entry><link linkend="view-pg-hba-rules"><structname>pg_hba_rules</structname></link></entry>
+      <entry>summary of client authentication configuration file contents</entry>
+     </row>
+
+     <row>
       <entry><link linkend="view-pg-group"><structname>pg_group</structname></link></entry>
       <entry>groups of database users</entry>
      </row>
@@ -8098,6 +8103,123 @@
 
 </sect1>
 
+ <sect1 id="view-pg-hba-rules">
+  <title><structname>pg_hba_rules</structname></title>
+
+  <indexterm zone="view-pg-hba-rules">
+   <primary>pg_hba_rules</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_hba_rules</structname> provides a summary of
+   the contents of the client authentication configuration file.  A row 
+   appears in this view for each entry appearing in the file, with annotations
+   indicating whether the rule could be applied successfully.
+  </para>
+
+  <para>
+   The <structname>pg_hba_rules</structname> view can be read only by
+   superusers.
+  </para>
+
+  <table>
+   <title><structname>pg_hba_rules</> Columns</title>
+
+  <tgroup cols="3">
+   <thead>
+    <row>
+     <entry>Name</entry>
+     <entry>Type</entry>
+     <entry>Description</entry>
+    </row>
+   </thead>
+   <tbody>
+    <row>
+     <entry><structfield>line_number</structfield></entry>
+     <entry><structfield>integer</structfield></entry>
+     <entry>
+      Line number within client authentication configuration file
+      the current value was set at
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>type</structfield></entry>
+     <entry><structfield>text</structfield></entry>
+     <entry>Type of connection</entry>
+    </row>
+    <row>
+     <entry><structfield>database</structfield></entry>
+     <entry><structfield>text[]</structfield></entry>
+     <entry>List of database name</entry>
+    </row>
+    <row>
+     <entry><structfield>user_name</structfield></entry>
+     <entry><structfield>text[]</structfield></entry>
+     <entry>List of user names</entry>
+    </row>
+    <row>
+     <entry><structfield>keyword_address</structfield></entry>
+     <entry><structfield>text</structfield></entry>
+     <entry>
+      List of keyword address names,
+      name can be all, samehost and samenet
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>address</structfield></entry>
+     <entry><structfield>inet</structfield></entry>
+     <entry>Client machine address</entry>
+    </row>
+    <row>
+     <entry><structfield>netmask</structfield></entry>
+     <entry><structfield>inet</structfield></entry>
+     <entry>Address mask</entry>
+    </row>
+    <row>
+     <entry><structfield>hostname</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Client host name</entry>
+    </row>
+    <row>
+     <entry><structfield>auth_method</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Authentication method</entry>
+    </row>
+    <row>
+     <entry><structfield>options</structfield></entry>
+     <entry><type>text[]</type></entry>
+     <entry>Configuration options set for authentication method</entry>
+    </row>
+    <row>
+     <entry><structfield>error</structfield></entry>
+     <entry><structfield>text</structfield></entry>
+     <entry>If not null, an error message indicating why this rule could not be loaded</entry>
+    </row>
+   </tbody>
+  </tgroup>
+  </table>
+
+  <para>
+   If the configuration file contains any problems, <structfield>error</structfield> field
+   indicating the problem of that rule. Following is the sample output of the view.
+  </para>
+  
+<programlisting>
+postgres=# select line_number, type, database, user_name, auth_method from pg_hba_rules;
+ line_number | type  | database | user_name | auth_method 
+-------------+-------+----------+-----------+-------------
+          84 | local | {all}    | {all}     | trust
+          86 | host  | {all}    | {all}     | trust
+          88 | host  | {all}    | {all}     | trust
+(3 rows)
+
+</programlisting>
+  <para>
+   See <xref linkend="client-authentication"> for more information about the various
+   ways to change client authentication configuration.
+  </para>
+ </sect1>
+
  <sect1 id="view-pg-group">
   <title><structname>pg_group</structname></title>
 
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index dda5891..f20486c 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -54,6 +54,13 @@
   database user names and OS user names.
  </para>
 
+ <para>
+  The system view
+  <link linkend="view-pg-hba-rules"><structname>pg_hba_rules</structname></link>
+  can be helpful for pre-testing changes to the client authentication configuration file, or for
+  diagnosing problems if loading of file did not have the desired effects.
+ </para>
+
  <sect1 id="auth-pg-hba-conf">
   <title>The <filename>pg_hba.conf</filename> File</title>
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 31aade1..8205405 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -450,6 +450,12 @@ CREATE VIEW pg_file_settings AS
 REVOKE ALL on pg_file_settings FROM PUBLIC;
 REVOKE EXECUTE ON FUNCTION pg_show_all_file_settings() FROM PUBLIC;
 
+CREATE VIEW pg_hba_rules AS
+   SELECT * FROM pg_hba_rules() AS A;
+
+REVOKE ALL on pg_hba_rules FROM PUBLIC;
+REVOKE EXECUTE ON FUNCTION pg_hba_rules() FROM PUBLIC;
+
 CREATE VIEW pg_timezone_abbrevs AS
     SELECT * FROM pg_timezone_abbrevs();
 
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 07f046f..d44fd03 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -25,15 +25,21 @@
 #include <arpa/inet.h>
 #include <unistd.h>
 
+#include "access/htup_details.h"
+#include "catalog/objectaddress.h"
 #include "catalog/pg_collation.h"
+#include "catalog/pg_type.h"
 #include "common/ip.h"
+#include "funcapi.h"
 #include "libpq/ifaddr.h"
 #include "libpq/libpq.h"
+#include "miscadmin.h"
 #include "postmaster/postmaster.h"
 #include "regex/regex.h"
 #include "replication/walsender.h"
 #include "storage/fd.h"
 #include "utils/acl.h"
+#include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
@@ -75,6 +81,15 @@ typedef struct HbaToken
 	bool		quoted;
 } HbaToken;
 
+
+/* Context to use with fill_hba_line function. */
+typedef struct FillHbaLineCxt
+{
+	MemoryContext memcxt;
+	TupleDesc	tupdesc;
+	Tuplestorestate *tuple_store;
+} FillHbaLineCxt;
+
 /*
  * pre-parsed content of HBA config file: list of HbaLine structs.
  * parsed_hba_context is the memory context where it lives.
@@ -99,7 +114,13 @@ static MemoryContext tokenize_file(const char *filename, FILE *file,
 static List *tokenize_inc_file(List *tokens, const char *outer_filename,
 				  const char *inc_filename);
 static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
-				   int line_num);
+				   int line_num, int level, char **err_msg);
+static Datum getauthmethod(UserAuth auth_method);
+static void fill_hba_auth_opt(Datum *optdata, char *optname, char *optvalue);
+static Datum gethba_options(HbaLine *hba);
+static void fill_hba_line(FillHbaLineCxt *context, int lineno,
+			  HbaLine *hba, const char *err_msg);
+static void fill_hba(FillHbaLineCxt *context);
 
 /*
  * isblank() exists in the ISO C99 spec, but it's not very portable yet,
@@ -748,11 +769,12 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
  *						 reporting error if it's not.
  */
 #define INVALID_AUTH_OPTION(optname, validmethods) do {\
-	ereport(LOG, \
+	*err_msg = psprintf(_("authentication option \"%s\" is only valid for authentication methods %s"), \
+						optname, _(validmethods)); \
+	ereport(level, \
 			(errcode(ERRCODE_CONFIG_FILE_ERROR), \
 			 /* translator: the second %s is a list of auth methods */ \
-			 errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
-					optname, _(validmethods)), \
+			 errmsg("%s", *err_msg), \
 			 errcontext("line %d of configuration file \"%s\"", \
 					line_num, HbaFileName))); \
 	return false; \
@@ -765,10 +787,11 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
 
 #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
 	if (argvar == NULL) {\
-		ereport(LOG, \
+		*err_msg = psprintf(_("authentication method \"%s\" requires argument \"%s\" to be set"), \
+						authname, argname); \
+		ereport(level, \
 				(errcode(ERRCODE_CONFIG_FILE_ERROR), \
-				 errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
-						authname, argname), \
+				 errmsg("%s", *err_msg), \
 				 errcontext("line %d of configuration file \"%s\"", \
 						line_num, HbaFileName))); \
 		return NULL; \
@@ -818,7 +841,8 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
  * NULL.
  */
 static HbaLine *
-parse_hba_line(List *line, int line_num, char *raw_line)
+parse_hba_line(List *line, int line_num, char *raw_line,
+			   int level, char **err_msg)
 {
 	char	   *str;
 	struct addrinfo *gai_result;
@@ -841,9 +865,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	tokens = lfirst(field);
 	if (tokens->length > 1)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("multiple values specified for connection type"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("multiple values specified for connection type"),
+				 errmsg("%s", *err_msg),
 				 errhint("Specify exactly one connection type per line."),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
@@ -855,9 +880,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 #ifdef HAVE_UNIX_SOCKETS
 		parsedline->conntype = ctLocal;
 #else
-		ereport(LOG,
+		*err_msg = pstrdup(_("local connections are not supported by this build"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("local connections are not supported by this build"),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -874,16 +900,20 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 			/* Log a warning if SSL support is not active */
 #ifdef USE_SSL
 			if (!EnableSSL)
-				ereport(LOG,
+			{
+				*err_msg = pstrdup(_("hostssl record cannot match because SSL is disabled"));
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				errmsg("hostssl record cannot match because SSL is disabled"),
+						 errmsg("%s", *err_msg),
 						 errhint("Set ssl = on in postgresql.conf."),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
+			}
 #else
-			ereport(LOG,
+			*err_msg = pstrdup(_("hostssl record cannot match because SSL is not supported by this build"));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("hostssl record cannot match because SSL is not supported by this build"),
+					 errmsg("%s", *err_msg),
 			  errhint("Compile with --with-openssl to use SSL connections."),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
@@ -901,10 +931,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	}							/* record type */
 	else
 	{
-		ereport(LOG,
+		*err_msg = psprintf(_("invalid connection type \"%s\""),
+							token->string);
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("invalid connection type \"%s\"",
-						token->string),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -914,9 +945,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	field = lnext(field);
 	if (!field)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("end-of-line before database specification"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("end-of-line before database specification"),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -933,9 +965,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	field = lnext(field);
 	if (!field)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("end-of-line before role specification"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("end-of-line before role specification"),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -954,9 +987,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 		field = lnext(field);
 		if (!field)
 		{
-			ereport(LOG,
+			*err_msg = pstrdup(_("end-of-line before IP address specification"));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("end-of-line before IP address specification"),
+					 errmsg("%s", *err_msg),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
 			return NULL;
@@ -964,9 +998,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 		tokens = lfirst(field);
 		if (tokens->length > 1)
 		{
-			ereport(LOG,
+			*err_msg = pstrdup(_("multiple values specified for host address"));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("multiple values specified for host address"),
+					 errmsg("%s", *err_msg),
 					 errhint("Specify one address range per line."),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
@@ -1019,10 +1054,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				parsedline->hostname = str;
 			else
 			{
-				ereport(LOG,
+				*err_msg = psprintf(_("invalid IP address \"%s\": %s"),
+									str, gai_strerror(ret));
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
-						 errmsg("invalid IP address \"%s\": %s",
-								str, gai_strerror(ret)),
+						 errmsg("%s", *err_msg),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
 				if (gai_result)
@@ -1037,10 +1073,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 			{
 				if (parsedline->hostname)
 				{
-					ereport(LOG,
+					*err_msg = psprintf(_("specifying both host name and CIDR mask is invalid: \"%s\""),
+										token->string);
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
-							 errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
-									token->string),
+							 errmsg("%s", *err_msg),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
 					return NULL;
@@ -1049,10 +1086,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
 										  parsedline->addr.ss_family) < 0)
 				{
-					ereport(LOG,
+					*err_msg = psprintf(_("invalid CIDR mask in address \"%s\""),
+										token->string);
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
-							 errmsg("invalid CIDR mask in address \"%s\"",
-									token->string),
+							 errmsg("%s", *err_msg),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
 					return NULL;
@@ -1066,9 +1104,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				field = lnext(field);
 				if (!field)
 				{
-					ereport(LOG,
+					*err_msg = pstrdup(_("end-of-line before netmask specification"));
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
-						  errmsg("end-of-line before netmask specification"),
+							 errmsg("%s", *err_msg),
 							 errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
@@ -1077,9 +1116,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				tokens = lfirst(field);
 				if (tokens->length > 1)
 				{
-					ereport(LOG,
+					*err_msg = pstrdup(_("multiple values specified for netmask"));
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
-							 errmsg("multiple values specified for netmask"),
+							 errmsg("%s", *err_msg),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
 					return NULL;
@@ -1090,10 +1130,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 										 &hints, &gai_result);
 				if (ret || !gai_result)
 				{
-					ereport(LOG,
+					*err_msg = psprintf(_("invalid IP mask \"%s\": %s"),
+										token->string, gai_strerror(ret));
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
-							 errmsg("invalid IP mask \"%s\": %s",
-									token->string, gai_strerror(ret)),
+							 errmsg("%s", *err_msg),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
 					if (gai_result)
@@ -1107,9 +1148,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 
 				if (parsedline->addr.ss_family != parsedline->mask.ss_family)
 				{
-					ereport(LOG,
+					*err_msg = pstrdup(_("IP address and mask do not match"));
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
-							 errmsg("IP address and mask do not match"),
+							 errmsg("%s", *err_msg),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
 					return NULL;
@@ -1122,9 +1164,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	field = lnext(field);
 	if (!field)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("end-of-line before authentication method"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("end-of-line before authentication method"),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -1132,9 +1175,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	tokens = lfirst(field);
 	if (tokens->length > 1)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("multiple values specified for authentication type"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("multiple values specified for authentication type"),
+				 errmsg("%s", *err_msg),
 				 errhint("Specify exactly one authentication type per line."),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
@@ -1169,9 +1213,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	{
 		if (Db_user_namespace)
 		{
-			ereport(LOG,
+			*err_msg = pstrdup(_("MD5 authentication is not supported when \"db_user_namespace\" is enabled"));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
+					 errmsg("%s", *err_msg),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
 			return NULL;
@@ -1206,10 +1251,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 		parsedline->auth_method = uaRADIUS;
 	else
 	{
-		ereport(LOG,
+		*err_msg = psprintf(_("invalid authentication method \"%s\""),
+							token->string);
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("invalid authentication method \"%s\"",
-						token->string),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -1217,10 +1263,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 
 	if (unsupauth)
 	{
-		ereport(LOG,
+		*err_msg = psprintf(_("invalid authentication method \"%s\": not supported by this build"),
+							token->string);
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("invalid authentication method \"%s\": not supported by this build",
-						token->string),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -1238,9 +1285,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	if (parsedline->conntype == ctLocal &&
 		parsedline->auth_method == uaGSS)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("gssapi authentication is not supported on local sockets"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-		   errmsg("gssapi authentication is not supported on local sockets"),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -1249,9 +1297,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	if (parsedline->conntype != ctLocal &&
 		parsedline->auth_method == uaPeer)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("peer authentication is only supported on local sockets"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-			errmsg("peer authentication is only supported on local sockets"),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -1266,9 +1315,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	if (parsedline->conntype != ctHostSSL &&
 		parsedline->auth_method == uaCert)
 	{
-		ereport(LOG,
+		*err_msg = pstrdup(_("cert authentication is only supported on hostssl connections"));
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("cert authentication is only supported on hostssl connections"),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return NULL;
@@ -1315,16 +1365,18 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				/*
 				 * Got something that's not a name=value pair.
 				 */
-				ereport(LOG,
+				*err_msg = psprintf(_("authentication option not in name=value format: %s"),
+									token->string);
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
-						 errmsg("authentication option not in name=value format: %s", token->string),
+						 errmsg("%s", *err_msg),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
 				return NULL;
 			}
 
 			*val++ = '\0';		/* str now holds "name", val holds "value" */
-			if (!parse_hba_auth_opt(str, val, parsedline, line_num))
+			if (!parse_hba_auth_opt(str, val, parsedline, line_num, level, err_msg))
 				/* parse_hba_auth_opt already logged the error message */
 				return NULL;
 			pfree(str);
@@ -1352,9 +1404,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				parsedline->ldapbindpasswd ||
 				parsedline->ldapsearchattribute)
 			{
-				ereport(LOG,
+				*err_msg = pstrdup(_("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"));
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
-						 errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
+						 errmsg("%s", *err_msg),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
 				return NULL;
@@ -1362,9 +1415,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 		}
 		else if (!parsedline->ldapbasedn)
 		{
-			ereport(LOG,
+			*err_msg = pstrdup(_("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
+					 errmsg("%s", *err_msg),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
 			return NULL;
@@ -1394,7 +1448,7 @@ parse_hba_line(List *line, int line_num, char *raw_line)
  * encounter an error.
  */
 static bool
-parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
+parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num, int level, char **err_msg)
 {
 #ifdef USE_LDAP
 	hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
@@ -1414,9 +1468,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 	{
 		if (hbaline->conntype != ctHostSSL)
 		{
-			ereport(LOG,
+			*err_msg = pstrdup(_("clientcert can only be configured for \"hostssl\" rows"));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-			errmsg("clientcert can only be configured for \"hostssl\" rows"),
+					 errmsg("%s", *err_msg),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
 			return false;
@@ -1429,9 +1484,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 		{
 			if (hbaline->auth_method == uaCert)
 			{
-				ereport(LOG,
+				*err_msg = pstrdup(_("clientcert can not be set to 0 when using \"cert\" authentication"));
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
-						 errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
+						 errmsg("%s", *err_msg),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
 				return false;
@@ -1465,18 +1521,23 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 		rc = ldap_url_parse(val, &urldata);
 		if (rc != LDAP_SUCCESS)
 		{
-			ereport(LOG,
+			*err_msg = psprintf(_("could not parse LDAP URL \"%s\": %s"),
+								val, ldap_err2string(rc));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
+					 errmsg("%s", *err_msg)));
 			return false;
 		}
 
 		if (strcmp(urldata->lud_scheme, "ldap") != 0)
 		{
-			ereport(LOG,
+			*err_msg = psprintf(_("unsupported LDAP URL scheme: %s"),
+								urldata->lud_scheme);
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-			errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
+					 errmsg("%s", *err_msg)));
 			ldap_free_urldesc(urldata);
+
 			return false;
 		}
 
@@ -1489,17 +1550,19 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 		hbaline->ldapscope = urldata->lud_scope;
 		if (urldata->lud_filter)
 		{
-			ereport(LOG,
+			*err_msg = pstrdup(_("filters not supported in LDAP URLs"));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("filters not supported in LDAP URLs")));
+					 errmsg("%s", *err_msg)));
 			ldap_free_urldesc(urldata);
 			return false;
 		}
 		ldap_free_urldesc(urldata);
 #else							/* not OpenLDAP */
-		ereport(LOG,
+		*err_msg = pstrdup(_("LDAP URLs not supported on this platform"));
+		ereport(level,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("LDAP URLs not supported on this platform")));
+				 errmsg("%s", *err_msg)));
 #endif   /* not OpenLDAP */
 	}
 	else if (strcmp(name, "ldaptls") == 0)
@@ -1521,9 +1584,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 		hbaline->ldapport = atoi(val);
 		if (hbaline->ldapport == 0)
 		{
-			ereport(LOG,
+			*err_msg = psprintf(_("invalid LDAP port number: \"%s\""), val);
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("invalid LDAP port number: \"%s\"", val),
+					 errmsg("%s", *err_msg),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
 			return false;
@@ -1609,10 +1673,11 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 		ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
 		if (ret || !gai_result)
 		{
-			ereport(LOG,
+			*err_msg = psprintf(_("could not translate RADIUS server name \"%s\" to address: %s"),
+								val, gai_strerror(ret));
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("could not translate RADIUS server name \"%s\" to address: %s",
-							val, gai_strerror(ret)),
+					 errmsg("%s", *err_msg),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
 			if (gai_result)
@@ -1628,9 +1693,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 		hbaline->radiusport = atoi(val);
 		if (hbaline->radiusport == 0)
 		{
-			ereport(LOG,
+			*err_msg = psprintf(_("invalid RADIUS port number: \"%s\""), val);
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
-					 errmsg("invalid RADIUS port number: \"%s\"", val),
+					 errmsg("%s", *err_msg),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
 			return false;
@@ -1648,10 +1714,11 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
 	}
 	else
 	{
-		ereport(LOG,
+		*err_msg = psprintf(_("unrecognized authentication option name: \"%s\""),
+							name);
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("unrecognized authentication option name: \"%s\"",
-						name),
+				 errmsg("%s", *err_msg),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
 		return false;
@@ -1802,8 +1869,9 @@ load_hba(void)
 	forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
 	{
 		HbaLine    *newline;
+		char	   *err_msg = NULL;
 
-		if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
+		if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line), LOG, &err_msg)) == NULL)
 		{
 			/*
 			 * Parse error in the file, so indicate there's a problem.  NB: a
@@ -2255,3 +2323,446 @@ hba_getauthmethod(hbaPort *port)
 {
 	check_hba(port);
 }
+
+/*
+ * Returns the Text Datum representation of authentication method
+ */
+static Datum
+getauthmethod(UserAuth auth_method)
+{
+	Datum		result;
+
+	switch (auth_method)
+	{
+		case uaReject:
+			result = CStringGetTextDatum("reject");
+			break;
+		case uaTrust:
+			result = CStringGetTextDatum("trust");
+			break;
+		case uaIdent:
+			result = CStringGetTextDatum("ident");
+			break;
+		case uaPassword:
+			result = CStringGetTextDatum("password");
+			break;
+		case uaMD5:
+			result = CStringGetTextDatum("md5");
+			break;
+		case uaGSS:
+			result = CStringGetTextDatum("gss");
+			break;
+		case uaSSPI:
+			result = CStringGetTextDatum("sspi");
+			break;
+		case uaPAM:
+			result = CStringGetTextDatum("pam");
+			break;
+		case uaLDAP:
+			result = CStringGetTextDatum("ldap");
+			break;
+		case uaCert:
+			result = CStringGetTextDatum("cert");
+			break;
+		case uaRADIUS:
+			result = CStringGetTextDatum("radius");
+			break;
+		case uaPeer:
+			result = CStringGetTextDatum("peer");
+			break;
+		default:
+			elog(ERROR, "unexpected authentication method in parsed HBA entry");
+			break;
+	}
+
+	return result;
+}
+
+static void
+fill_hba_auth_opt(Datum *optdata, char *optname, char *optvalue)
+{
+	StringInfoData str;
+
+	initStringInfo(&str);
+	appendStringInfoString(&str, optname);
+	appendStringInfoString(&str, optvalue);
+	*optdata = CStringGetTextDatum(str.data);
+}
+
+/* LDAP supports 10 currently, keep this well above the most any method needs */
+#define MAX_OPTIONS 12
+
+static Datum
+gethba_options(HbaLine *hba)
+{
+	int			noptions;
+	Datum		options[MAX_OPTIONS];
+	char		buffer[64];
+
+	noptions = 0;
+
+	if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
+	{
+		if (hba->include_realm)
+			options[noptions++] = CStringGetTextDatum("include_realm=true");
+
+		if (hba->krb_realm)
+			fill_hba_auth_opt(&options[noptions++], "krb_realm=", hba->krb_realm);
+	}
+
+	if (hba->usermap)
+		fill_hba_auth_opt(&options[noptions++], "map=", hba->usermap);
+
+	if (hba->clientcert)
+		options[noptions++] = CStringGetTextDatum("clientcert=true");
+
+	if (hba->pamservice)
+		fill_hba_auth_opt(&options[noptions++], "pamservice=", hba->pamservice);
+
+	if (hba->auth_method == uaLDAP)
+	{
+		if (hba->ldapserver)
+			fill_hba_auth_opt(&options[noptions++], "ldapserver=", hba->ldapserver);
+
+		if (hba->ldapport)
+		{
+			snprintf(buffer, sizeof(buffer), "%d", hba->ldapport);
+			fill_hba_auth_opt(&options[noptions++], "ldapport=", buffer);
+		}
+
+		if (hba->ldaptls)
+			options[noptions++] = CStringGetTextDatum("ldaptls=true");
+
+		if (hba->ldapprefix)
+			fill_hba_auth_opt(&options[noptions++], "ldapprefix=", hba->ldapprefix);
+
+		if (hba->ldapsuffix)
+			fill_hba_auth_opt(&options[noptions++], "ldapsuffix=", hba->ldapsuffix);
+
+		if (hba->ldapbasedn)
+			fill_hba_auth_opt(&options[noptions++], "ldapbasedn=", hba->ldapbasedn);
+
+		if (hba->ldapbinddn)
+			fill_hba_auth_opt(&options[noptions++], "ldapbinddn=", hba->ldapbinddn);
+
+		if (hba->ldapbindpasswd)
+			fill_hba_auth_opt(&options[noptions++], "ldapbindpasswd=", hba->ldapbindpasswd);
+
+		if (hba->ldapsearchattribute)
+			fill_hba_auth_opt(&options[noptions++], "ldapsearchattribute=", hba->ldapsearchattribute);
+
+		if (hba->ldapscope)
+		{
+			snprintf(buffer, sizeof(buffer), "%d", hba->ldapscope);
+			fill_hba_auth_opt(&options[noptions++], "ldapscope=", buffer);
+		}
+	}
+
+	if (hba->auth_method == uaRADIUS)
+	{
+		if (hba->radiusserver)
+			fill_hba_auth_opt(&options[noptions++], "radiusserver=", hba->radiusserver);
+
+		if (hba->radiussecret)
+			fill_hba_auth_opt(&options[noptions++], "radiussecret=", hba->radiussecret);
+
+		if (hba->radiusidentifier)
+			fill_hba_auth_opt(&options[noptions++], "radiusidentifier=", hba->radiusidentifier);
+
+		if (hba->radiusport)
+		{
+			snprintf(buffer, sizeof(buffer), "%d", hba->radiusport);
+			fill_hba_auth_opt(&options[noptions++], "radiusport=", buffer);
+		}
+	}
+
+	Assert(noptions <= MAX_OPTIONS);
+	if (noptions)
+		return PointerGetDatum(
+				construct_array(options, noptions, TEXTOID, -1, false, 'i'));
+	return PointerGetDatum(NULL);
+}
+
+#define NUM_PG_HBA_LOOKUP_ATTS	 11
+
+static void
+fill_hba_line(FillHbaLineCxt *context, int lineno, HbaLine *hba, const char *err_msg)
+{
+	Datum		values[NUM_PG_HBA_LOOKUP_ATTS];
+	bool		nulls[NUM_PG_HBA_LOOKUP_ATTS];
+	ListCell   *dbcell;
+	char		buffer[NI_MAXHOST];
+	HeapTuple	tuple;
+	int			index;
+	Datum		options;
+	MemoryContext old_cxt;
+
+	index = 0;
+	memset(values, 0, sizeof(values));
+	memset(nulls, 0, sizeof(nulls));
+
+	old_cxt = MemoryContextSwitchTo(context->memcxt);
+
+	/* line_number */
+	values[index] = Int32GetDatum(lineno);
+
+	if (err_msg)
+	{
+		/* set all remaining columns as NULL, except error column */
+		memset(&nulls[1], true, (NUM_PG_HBA_LOOKUP_ATTS - 2));
+
+		/* error */
+		values[NUM_PG_HBA_LOOKUP_ATTS - 1] = CStringGetTextDatum(err_msg);
+	}
+	else
+	{
+		/* type */
+		index++;
+		switch (hba->conntype)
+		{
+			case ctLocal:
+				values[index] = CStringGetTextDatum("local");
+				break;
+			case ctHost:
+				values[index] = CStringGetTextDatum("host");
+				break;
+			case ctHostSSL:
+				values[index] = CStringGetTextDatum("hostssl");
+				break;
+			case ctHostNoSSL:
+				values[index] = CStringGetTextDatum("hostnossl");
+				break;
+			default:
+				elog(ERROR, "unexpected connection type in parsed HBA entry");
+		}
+
+		/* database */
+		index++;
+		if (list_length(hba->databases) != 0)
+		{
+			List	   *names = NULL;
+			HbaToken   *tok;
+
+			foreach(dbcell, hba->databases)
+			{
+				tok = lfirst(dbcell);
+				names = lappend(names, tok->string);
+			}
+
+			/* database */
+			Assert (names != NULL);
+				values[index] = PointerGetDatum(strlist_to_textarray(names));
+		}
+		else
+			nulls[index] = true;
+
+		/* user */
+		index++;
+		if (list_length(hba->roles) != 0)
+		{
+			List	   *roles = NULL;
+			HbaToken   *tok;
+
+			foreach(dbcell, hba->roles)
+			{
+				tok = lfirst(dbcell);
+				roles = lappend(roles, tok->string);
+			}
+
+			/* user */
+			Assert (roles != NULL);
+			values[index] = PointerGetDatum(strlist_to_textarray(roles));
+		}
+		else
+			nulls[index] = true;
+
+
+		/* keyword_address */
+		index++;
+		switch (hba->ip_cmp_method)
+		{
+			case ipCmpAll:
+				values[index] = CStringGetTextDatum("all");
+				break;
+			case ipCmpSameHost:
+				values[index] = CStringGetTextDatum("samehost");
+				break;
+			case ipCmpSameNet:
+				values[index] = CStringGetTextDatum("samenet");
+				break;
+			default:
+				nulls[index] = true;
+				break;
+		}
+
+		/* address */
+		index++;
+		if (pg_getnameinfo_all(&hba->addr, sizeof(struct sockaddr_storage),
+							   buffer, sizeof(buffer),
+							   NULL, 0,
+							   NI_NUMERICHOST) == 0)
+		{
+			clean_ipv6_addr(hba->addr.ss_family, buffer);
+			values[index] = DirectFunctionCall1(inet_in, CStringGetDatum(buffer));
+		}
+		else
+			nulls[index] = true;
+
+		/* netmask */
+		index++;
+		if (pg_getnameinfo_all(&hba->mask, sizeof(struct sockaddr_storage),
+							   buffer, sizeof(buffer),
+							   NULL, 0,
+							   NI_NUMERICHOST) == 0)
+		{
+			clean_ipv6_addr(hba->mask.ss_family, buffer);
+			values[index] = DirectFunctionCall1(inet_in, CStringGetDatum(buffer));
+		}
+		else
+			nulls[index] = true;
+
+		/* hostname */
+		index++;
+		if (hba->hostname)
+			values[index] = CStringGetTextDatum(hba->hostname);
+		else
+			nulls[index] = true;
+
+		/* method */
+		index++;
+		values[index] = getauthmethod(hba->auth_method);
+
+		/* options */
+		index++;
+		options = gethba_options(hba);
+		if (options)
+			values[index] = PointerGetDatum(options);
+		else
+			nulls[index] = true;
+
+		/* error */
+		index++;
+		nulls[index] = true;
+	}
+
+	tuple = heap_form_tuple(context->tupdesc, values, nulls);
+	tuplestore_puttuple(context->tuple_store, tuple);
+
+	MemoryContextSwitchTo(old_cxt);
+	return;
+}
+
+/*
+ * Read the config file and fill the HbaLine records for the view.
+ */
+static void
+fill_hba(FillHbaLineCxt *context)
+{
+	FILE	   *file;
+	List	   *hba_lines = NIL;
+	List	   *hba_line_nums = NIL;
+	List	   *hba_raw_lines = NIL;
+	ListCell   *line,
+			   *line_num,
+			   *raw_line;
+	MemoryContext linecxt;
+	MemoryContext oldcxt;
+	MemoryContext hbacxt;
+
+	file = AllocateFile(HbaFileName, "r");
+	if (file == NULL)
+	{
+		ereport(LOG,
+				(errcode_for_file_access(),
+				 errmsg("could not open configuration file \"%s\": %m",
+						HbaFileName)));
+		return;
+	}
+
+	linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
+	FreeFile(file);
+
+	/* Now parse all the lines */
+	hbacxt = AllocSetContextCreate(CurrentMemoryContext,
+								   "hba parser context",
+								   ALLOCSET_SMALL_SIZES);
+	oldcxt = MemoryContextSwitchTo(hbacxt);
+	forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
+	{
+		HbaLine    *newline;
+		int			lineno = lfirst_int(line_num);
+		char	   *err_msg = NULL;
+
+		MemoryContextReset(hbacxt);
+		newline = parse_hba_line(lfirst(line), lineno, lfirst(raw_line), DEBUG3, &err_msg);
+		fill_hba_line(context, lineno, newline, err_msg);
+	}
+
+	/* Free tokenizer memory */
+	MemoryContextDelete(linecxt);
+	MemoryContextSwitchTo(oldcxt);
+	MemoryContextDelete(hbacxt);
+}
+
+/*
+ * SQL-accessible SRF to return all the settings from the pg_hba.conf
+ * file.
+ */
+Datum
+hba_rules(PG_FUNCTION_ARGS)
+{
+	Tuplestorestate *tuple_store;
+	TupleDesc	tupdesc;
+	MemoryContext old_cxt;
+	FillHbaLineCxt *mycxt;
+	ReturnSetInfo *rsi;
+
+	/*
+	 * We must use the Materialize mode to be safe against HBA file reloads
+	 * while the cursor is open. It's also more efficient than having to look
+	 * up our current position in the parsed list every time.
+	 */
+	rsi = (ReturnSetInfo *) fcinfo->resultinfo;
+
+	/* Check to see if caller supports us returning a tuplestore */
+	if (rsi == NULL || !IsA(rsi, ReturnSetInfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("set-valued function called in context that cannot accept a set")));
+	if (!(rsi->allowedModes & SFRM_Materialize))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("materialize mode required, but it is not " \
+						"allowed in this context")));
+
+	rsi->returnMode = SFRM_Materialize;
+
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	/* Build tuplestore to hold the result rows */
+	old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+
+	tuple_store =
+		tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
+							  false, work_mem);
+	rsi->setDesc = tupdesc;
+	rsi->setResult = tuple_store;
+
+	MemoryContextSwitchTo(old_cxt);
+
+	mycxt = (FillHbaLineCxt *) palloc(sizeof(FillHbaLineCxt));
+	mycxt->memcxt = AllocSetContextCreate(CurrentMemoryContext,
+										  "pg_hba_lookup tuple cxt",
+										  ALLOCSET_DEFAULT_SIZES);
+	mycxt->tupdesc = tupdesc;
+	mycxt->tuple_store = tuple_store;
+
+	fill_hba(mycxt);
+
+	MemoryContextDelete(mycxt->memcxt);
+	pfree(mycxt);
+
+	PG_RETURN_NULL();
+}
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 37e022d..fe81d05 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3070,6 +3070,8 @@ DATA(insert OID = 2084 (  pg_show_all_settings	PGNSP PGUID 12 1 1000 0 0 f f f f
 DESCR("SHOW ALL as a function");
 DATA(insert OID = 3329 (  pg_show_all_file_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{25,23,23,25,25,16,25}" "{o,o,o,o,o,o,o}" "{sourcefile,sourceline,seqno,name,setting,applied,error}" _null_ _null_ show_all_file_settings _null_ _null_ _null_ ));
 DESCR("show config file settings");
+DATA(insert OID = 3343 (  pg_hba_rules PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{23,25,1009,1009,25,869,869,25,25,1009,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{line_number,type,database,user_name,keyword_address,address,netmask,hostname,auth_method,options,error}" _null_ _null_ hba_rules _null_ _null_ _null_ ));
+DESCR("show pg_hba config rules");
 DATA(insert OID = 1371 (  pg_lock_status   PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{25,26,26,23,21,25,28,26,26,21,25,23,25,16,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid,virtualtransaction,pid,mode,granted,fastpath}" _null_ _null_ pg_lock_status _null_ _null_ _null_ ));
 DESCR("view system lock information");
 DATA(insert OID = 2561 (  pg_blocking_pids PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 1007 "23" _null_ _null_ _null_ _null_ _null_ pg_blocking_pids _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index e1bb344..7595a19 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1190,6 +1190,9 @@ extern Datum pg_control_recovery(PG_FUNCTION_ARGS);
 extern Datum row_security_active(PG_FUNCTION_ARGS);
 extern Datum row_security_active_name(PG_FUNCTION_ARGS);
 
+/* hba.c */
+extern Datum hba_rules(PG_FUNCTION_ARGS);
+
 /* lockfuncs.c */
 extern Datum pg_lock_status(PG_FUNCTION_ARGS);
 extern Datum pg_blocking_pids(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e9cfadb..fe24168 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1338,6 +1338,20 @@ pg_group| SELECT pg_authid.rolname AS groname,
           WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist
    FROM pg_authid
   WHERE (NOT pg_authid.rolcanlogin);
+pg_hba_rules| SELECT a.line_number,
+    a.type,
+    a.keyword_database,
+    a.database,
+    a.keyword_user,
+    a.user_name,
+    a.keyword_address,
+    a.address,
+    a.netmask,
+    a.hostname,
+    a.method,
+    a.options,
+    a.error
+   FROM pg_hba_rules() a(line_number, type, keyword_database, database, keyword_user, user_name, keyword_address, address, netmask, hostname, method, options, error);
 pg_indexes| SELECT n.nspname AS schemaname,
     c.relname AS tablename,
     i.relname AS indexname,
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 993880d..668d46a 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -604,6 +604,7 @@ FileFdwExecutionState
 FileFdwPlanState
 FileName
 FileNameMap
+FillHbaLineCxt
 FindSplitData
 FixedParallelState
 FixedParamState
