diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 4e09e06..91fa9b7 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7319,6 +7319,11 @@
      </row>
 
      <row>
+      <entry><link linkend="view-pg-hba-file-settings"><structname>pg_hba_file_settings</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>
@@ -7852,6 +7857,131 @@
 
 </sect1>
 
+ <sect1 id="view-pg-hba-file-settings">
+  <title><structname>pg_hba_file_settings</structname></title>
+
+  <indexterm zone="view-pg-hba-file-settings">
+   <primary>pg_hba_file_settings</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_hba_file_settings</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_file_settings</structname> view can be read only by
+   superusers.
+  </para>
+
+  <table>
+   <title><structname>pg_hba_file_settings</> 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>keyword_database</structfield></entry>
+     <entry><structfield>text[]</structfield></entry>
+     <entry>
+      List of keyword database names,
+      name can be all, sameuser, samerole, replication and samegroup
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>database</structfield></entry>
+     <entry><structfield>text[]</structfield></entry>
+     <entry>List of database name</entry>
+    </row>
+    <row>
+     <entry><structfield>keyword_user</structfield></entry>
+     <entry><structfield>text[]</structfield></entry>
+     <entry>
+      List of keyword user names,
+      name can be all and a group name prefixed with "+"
+     </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>method</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Authentication method</entry>
+    </row>
+    <row>
+     <entry><structfield>options</structfield></entry>
+     <entry><type>jsonb</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 error related to this entry
+     </entry>
+    </row>
+   </tbody>
+  </tgroup>
+  </table>
+
+  <para>
+   If the configuration file contains any errors, <structfield>error</structfield> field
+   indicating the problem.
+  </para>
+
+  <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 ca262d9..a695c2c 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-file-settings"><structname>pg_hba_file_settings</structname></link>
+  can be helpful for pre-testing changes to the client authentication configuration file, or for
+  diagnosing problems if a <systemitem>SIGHUP</> signal 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 4fc5d5a..42afd57 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -427,6 +427,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_file_settings AS
+   SELECT * FROM pg_hba_file_settings() AS A;
+
+REVOKE ALL on pg_hba_file_settings FROM PUBLIC;
+REVOKE EXECUTE ON FUNCTION pg_hba_file_settings() 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 1b4bbce..046c61c 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -25,15 +25,22 @@
 #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 "funcapi.h"
 #include "libpq/ip.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/jsonb.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 
@@ -74,6 +81,15 @@ typedef struct HbaToken
 	bool		quoted;
 } HbaToken;
 
+
+/* Context to use with lookup_hba_line_callback function. */
+typedef struct LookupHbaLineCxt
+{
+	MemoryContext memcxt;
+	TupleDesc	tupdesc;
+	Tuplestorestate *tuple_store;
+} LookupHbaLineCxt;
+
 /*
  * pre-parsed content of HBA config file: list of HbaLine structs.
  * parsed_hba_context is the memory context where it lives.
@@ -99,6 +115,10 @@ 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);
+static Datum getauthmethod(UserAuth auth_method);
+static Jsonb *gethba_options(HbaLine *hba);
+static void lookup_hba_line_callback(void *context, int lineno, HbaLine *hba, const char *err_msg);
+static bool token_is_a_database_keyword(HbaToken *tok);
 
 /*
  * isblank() exists in the ISO C99 spec, but it's not very portable yet,
@@ -819,7 +839,7 @@ 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, char **err_msg, int level)
 {
 	char	   *str;
 	struct addrinfo *gai_result;
@@ -842,12 +862,13 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	tokens = lfirst(field);
 	if (tokens->length > 1)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("multiple values specified for connection type"),
 				 errhint("Specify exactly one connection type per line."),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("multiple values specified for connection type"));
 		return NULL;
 	}
 	token = linitial(tokens);
@@ -856,11 +877,12 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 #ifdef HAVE_UNIX_SOCKETS
 		parsedline->conntype = ctLocal;
 #else
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("local connections are not supported by this build"),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("local connections are not supported by this build"));
 		return NULL;
 #endif
 	}
@@ -877,21 +899,23 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				parsedline->conntype = ctHostSSL;
 			else
 			{
-				ereport(LOG,
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
 						 errmsg("hostssl requires SSL to be turned on"),
 						 errhint("Set ssl = on in postgresql.conf."),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
+				*err_msg = pstrdup(_("hostssl requires SSL to be turned on"));
 				return NULL;
 			}
 #else
-			ereport(LOG,
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
 					 errmsg("hostssl is not supported by this build"),
 			  errhint("Compile with --with-openssl to use SSL connections."),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
+			*err_msg = pstrdup(_("hostssl is not supported by this build"));
 			return NULL;
 #endif
 		}
@@ -907,12 +931,13 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	}							/* record type */
 	else
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("invalid connection type \"%s\"",
 						token->string),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("invalid connection type"));
 		return NULL;
 	}
 
@@ -920,11 +945,12 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	field = lnext(field);
 	if (!field)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("end-of-line before database specification"),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("end-of-line before database specification"));
 		return NULL;
 	}
 	parsedline->databases = NIL;
@@ -939,11 +965,12 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	field = lnext(field);
 	if (!field)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("end-of-line before role specification"),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("end-of-line before role specification"));
 		return NULL;
 	}
 	parsedline->roles = NIL;
@@ -960,22 +987,24 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 		field = lnext(field);
 		if (!field)
 		{
-			ereport(LOG,
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
 					 errmsg("end-of-line before IP address specification"),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
+			*err_msg = pstrdup(_("end-of-line before IP address specification"));
 			return NULL;
 		}
 		tokens = lfirst(field);
 		if (tokens->length > 1)
 		{
-			ereport(LOG,
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
 					 errmsg("multiple values specified for host address"),
 					 errhint("Specify one address range per line."),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
+			*err_msg = pstrdup(_("multiple values specified for host address"));
 			return NULL;
 		}
 		token = linitial(tokens);
@@ -1025,7 +1054,7 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				parsedline->hostname = str;
 			else
 			{
-				ereport(LOG,
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
 						 errmsg("invalid IP address \"%s\": %s",
 								str, gai_strerror(ret)),
@@ -1033,6 +1062,7 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 									line_num, HbaFileName)));
 				if (gai_result)
 					pg_freeaddrinfo_all(hints.ai_family, gai_result);
+				*err_msg = pstrdup(_("invalid IP address"));
 				return NULL;
 			}
 
@@ -1043,24 +1073,26 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 			{
 				if (parsedline->hostname)
 				{
-					ereport(LOG,
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
 							 errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
 									token->string),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
+					*err_msg = pstrdup(_("specifying both host name and CIDR mask is invalid"));
 					return NULL;
 				}
 
 				if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
 										  parsedline->addr.ss_family) < 0)
 				{
-					ereport(LOG,
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
 							 errmsg("invalid CIDR mask in address \"%s\"",
 									token->string),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
+					*err_msg = pstrdup(_("invalid CIDR mask in address"));
 					return NULL;
 				}
 				pfree(str);
@@ -1072,22 +1104,24 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				field = lnext(field);
 				if (!field)
 				{
-					ereport(LOG,
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
 						  errmsg("end-of-line before netmask specification"),
 							 errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
+					*err_msg = pstrdup(_("end-of-line before netmask specification"));
 					return NULL;
 				}
 				tokens = lfirst(field);
 				if (tokens->length > 1)
 				{
-					ereport(LOG,
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
 							 errmsg("multiple values specified for netmask"),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
+					*err_msg = pstrdup(_("multiple values specified for netmask"));
 					return NULL;
 				}
 				token = linitial(tokens);
@@ -1096,7 +1130,7 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 										 &hints, &gai_result);
 				if (ret || !gai_result)
 				{
-					ereport(LOG,
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
 							 errmsg("invalid IP mask \"%s\": %s",
 									token->string, gai_strerror(ret)),
@@ -1104,6 +1138,7 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 									  line_num, HbaFileName)));
 					if (gai_result)
 						pg_freeaddrinfo_all(hints.ai_family, gai_result);
+					*err_msg = pstrdup(_("invalid IP mask"));
 					return NULL;
 				}
 
@@ -1113,11 +1148,12 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 
 				if (parsedline->addr.ss_family != parsedline->mask.ss_family)
 				{
-					ereport(LOG,
+					ereport(level,
 							(errcode(ERRCODE_CONFIG_FILE_ERROR),
 							 errmsg("IP address and mask do not match"),
 						   errcontext("line %d of configuration file \"%s\"",
 									  line_num, HbaFileName)));
+					*err_msg = pstrdup(_("IP address and mask do not match"));
 					return NULL;
 				}
 			}
@@ -1128,22 +1164,24 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	field = lnext(field);
 	if (!field)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("end-of-line before authentication method"),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("end-of-line before authentication method"));
 		return NULL;
 	}
 	tokens = lfirst(field);
 	if (tokens->length > 1)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("multiple values specified for authentication type"),
 				 errhint("Specify exactly one authentication type per line."),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("multiple values specified for authentication type"));
 		return NULL;
 	}
 	token = linitial(tokens);
@@ -1175,11 +1213,12 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	{
 		if (Db_user_namespace)
 		{
-			ereport(LOG,
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
 					 errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
+			*err_msg = pstrdup(_("MD5 authentication is not supported when \"db_user_namespace\" is enabled"));
 			return NULL;
 		}
 		parsedline->auth_method = uaMD5;
@@ -1212,23 +1251,25 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 		parsedline->auth_method = uaRADIUS;
 	else
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("invalid authentication method \"%s\"",
 						token->string),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("invalid authentication method"));
 		return NULL;
 	}
 
 	if (unsupauth)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("invalid authentication method \"%s\": not supported by this build",
 						token->string),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("invalid authentication method, not supported by this build"));
 		return NULL;
 	}
 
@@ -1244,22 +1285,24 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	if (parsedline->conntype == ctLocal &&
 		parsedline->auth_method == uaGSS)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 		   errmsg("gssapi authentication is not supported on local sockets"),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("gssapi authentication is not supported on local sockets"));
 		return NULL;
 	}
 
 	if (parsedline->conntype != ctLocal &&
 		parsedline->auth_method == uaPeer)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 			errmsg("peer authentication is only supported on local sockets"),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("peer authentication is only supported on local sockets"));
 		return NULL;
 	}
 
@@ -1272,11 +1315,12 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 	if (parsedline->conntype != ctHostSSL &&
 		parsedline->auth_method == uaCert)
 	{
-		ereport(LOG,
+		ereport(level,
 				(errcode(ERRCODE_CONFIG_FILE_ERROR),
 				 errmsg("cert authentication is only supported on hostssl connections"),
 				 errcontext("line %d of configuration file \"%s\"",
 							line_num, HbaFileName)));
+		*err_msg = pstrdup(_("cert authentication is only supported on hostssl connections"));
 		return NULL;
 	}
 
@@ -1321,11 +1365,12 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				/*
 				 * Got something that's not a name=value pair.
 				 */
-				ereport(LOG,
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
 						 errmsg("authentication option not in name=value format: %s", token->string),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
+				*err_msg = pstrdup(_("authentication option not in name=value format"));
 				return NULL;
 			}
 
@@ -1358,21 +1403,23 @@ parse_hba_line(List *line, int line_num, char *raw_line)
 				parsedline->ldapbindpasswd ||
 				parsedline->ldapsearchattribute)
 			{
-				ereport(LOG,
+				ereport(level,
 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
 						 errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
 						 errcontext("line %d of configuration file \"%s\"",
 									line_num, HbaFileName)));
+				*err_msg = pstrdup(_("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"));
 				return NULL;
 			}
 		}
 		else if (!parsedline->ldapbasedn)
 		{
-			ereport(LOG,
+			ereport(level,
 					(errcode(ERRCODE_CONFIG_FILE_ERROR),
 					 errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
 					 errcontext("line %d of configuration file \"%s\"",
 								line_num, HbaFileName)));
+			*err_msg = pstrdup(_("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"));
 			return NULL;
 		}
 	}
@@ -1785,7 +1832,7 @@ check_hba(hbaPort *port)
  * with the old data.
  */
 bool
-load_hba(void)
+load_hba(hba_line_callback callback, void *callback_context)
 {
 	FILE	   *file;
 	List	   *hba_lines = NIL;
@@ -1799,6 +1846,8 @@ load_hba(void)
 	MemoryContext linecxt;
 	MemoryContext oldcxt;
 	MemoryContext hbacxt;
+	char	*err_msg = NULL;
+	int log_level = LOG;
 
 	file = AllocateFile(HbaFileName, "r");
 	if (file == NULL)
@@ -1813,9 +1862,11 @@ load_hba(void)
 	linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
 	FreeFile(file);
 
+	if (callback)
+		log_level = DEBUG3;
+
 	/* Now parse all the lines */
-	Assert(PostmasterContext);
-	hbacxt = AllocSetContextCreate(PostmasterContext,
+	hbacxt = AllocSetContextCreate(CurrentMemoryContext,
 								   "hba parser context",
 								   ALLOCSET_DEFAULT_MINSIZE,
 								   ALLOCSET_DEFAULT_MINSIZE,
@@ -1824,9 +1875,13 @@ load_hba(void)
 	forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
 	{
 		HbaLine    *newline;
+		int lineno = lfirst_int(line_num);
 
-		if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
+		if ((newline = parse_hba_line(lfirst(line), lineno, lfirst(raw_line), &err_msg, log_level)) == NULL)
 		{
+			if (callback)
+				callback(callback_context, lineno, newline, err_msg);
+
 			/*
 			 * Parse error in the file, so indicate there's a problem.  NB: a
 			 * problem in a line will free the memory for all previous lines
@@ -1844,10 +1899,24 @@ load_hba(void)
 			continue;
 		}
 
+		if (callback)
+			callback(callback_context, lineno, newline, NULL);
 		new_parsed_lines = lappend(new_parsed_lines, newline);
 	}
 
 	/*
+	 * If callback function is available, then don't update the
+	 * saved authentication rules.
+	 */
+	if (callback)
+	{
+		MemoryContextDelete(linecxt);
+		MemoryContextSwitchTo(oldcxt);
+		MemoryContextDelete(hbacxt);
+		return true;
+	}
+
+	/*
 	 * A valid HBA file must have at least one entry; else there's no way to
 	 * connect to the postmaster.  But only complain about this if we didn't
 	 * already have parsing errors.
@@ -1873,14 +1942,25 @@ load_hba(void)
 	}
 
 	/* Loaded new file successfully, replace the one we use */
-	if (parsed_hba_context != NULL)
-		MemoryContextDelete(parsed_hba_context);
+	discard_hba();
 	parsed_hba_context = hbacxt;
 	parsed_hba_lines = new_parsed_lines;
 
 	return true;
 }
 
+void
+discard_hba(void)
+{
+	if (parsed_hba_context != NULL)
+	{
+		MemoryContextDelete(parsed_hba_context);
+		parsed_hba_context = NULL;
+		parsed_hba_lines = NIL;
+	}
+}
+
+
 /*
  * Parse one tokenised line from the ident config file and store the result in
  * an IdentLine structure, or NULL if parsing fails.
@@ -2192,8 +2272,7 @@ load_ident(void)
 	FreeFile(file);
 
 	/* Now parse all the lines */
-	Assert(PostmasterContext);
-	ident_context = AllocSetContextCreate(PostmasterContext,
+	ident_context = AllocSetContextCreate(CurrentMemoryContext,
 										  "ident parser context",
 										  ALLOCSET_DEFAULT_MINSIZE,
 										  ALLOCSET_DEFAULT_MINSIZE,
@@ -2246,6 +2325,19 @@ load_ident(void)
 	}
 
 	/* Loaded new file successfully, replace the one we use */
+	discard_ident();
+	parsed_ident_context = ident_context;
+	parsed_ident_lines = new_parsed_lines;
+
+	return true;
+}
+
+void
+discard_ident(void)
+{
+	ListCell   *parsed_line_cell;
+	IdentLine  *newline;
+
 	if (parsed_ident_lines != NIL)
 	{
 		foreach(parsed_line_cell, parsed_ident_lines)
@@ -2254,14 +2346,15 @@ load_ident(void)
 			if (newline->ident_user[0] == '/')
 				pg_regfree(&newline->re);
 		}
+
+		parsed_ident_lines = NIL;
 	}
+
 	if (parsed_ident_context != NULL)
+	{
 		MemoryContextDelete(parsed_ident_context);
-
-	parsed_ident_context = ident_context;
-	parsed_ident_lines = new_parsed_lines;
-
-	return true;
+		parsed_ident_context = NULL;
+	}
 }
 
 
@@ -2279,3 +2372,545 @@ 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 Jsonb *
+gethba_options(HbaLine *hba)
+{
+	JsonbParseState *parseState = NULL;
+	JsonbValue *result;
+
+	result = pushJsonbValue(&parseState, WJB_BEGIN_OBJECT, NULL);
+
+	if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
+	{
+		if (hba->include_realm)
+		{
+			push_jsonb_string_key(&parseState, "include_realm");
+			push_jsonb_bool_value(&parseState, true);
+		}
+
+		if (hba->krb_realm)
+		{
+			push_jsonb_string_key(&parseState, "krb_realm");
+			push_jsonb_string_value(&parseState, hba->krb_realm);
+		}
+	}
+
+	if (hba->usermap)
+	{
+		push_jsonb_string_key(&parseState, "map");
+		push_jsonb_string_value(&parseState, hba->usermap);
+	}
+
+	if (hba->clientcert)
+	{
+		push_jsonb_string_key(&parseState, "clientcert");
+		push_jsonb_bool_value(&parseState, true);
+	}
+
+	if (hba->pamservice)
+	{
+		push_jsonb_string_key(&parseState, "pamservice");
+		push_jsonb_string_value(&parseState, hba->pamservice);
+	}
+
+	if (hba->auth_method == uaLDAP)
+	{
+		if (hba->ldapserver)
+		{
+			push_jsonb_string_key(&parseState, "ldapserver");
+			push_jsonb_string_value(&parseState, hba->ldapserver);
+		}
+
+		if (hba->ldapport)
+		{
+			push_jsonb_string_key(&parseState, "ldapport");
+			push_jsonb_int32_value(&parseState, hba->ldapport);
+		}
+
+		if (hba->ldaptls)
+		{
+			push_jsonb_string_key(&parseState, "ldaptls");
+			push_jsonb_bool_value(&parseState, true);
+		}
+
+		if (hba->ldapprefix)
+		{
+			push_jsonb_string_key(&parseState, "ldapprefix");
+			push_jsonb_string_value(&parseState, hba->ldapprefix);
+		}
+
+		if (hba->ldapsuffix)
+		{
+			push_jsonb_string_key(&parseState, "ldapsuffix");
+			push_jsonb_string_value(&parseState, hba->ldapsuffix);
+		}
+
+		if (hba->ldapbasedn)
+		{
+			push_jsonb_string_key(&parseState, "ldapbasedn");
+			push_jsonb_string_value(&parseState, hba->ldapbasedn);
+		}
+
+		if (hba->ldapbinddn)
+		{
+			push_jsonb_string_key(&parseState, "ldapbinddn");
+			push_jsonb_string_value(&parseState, hba->ldapbinddn);
+		}
+
+		if (hba->ldapbindpasswd)
+		{
+			push_jsonb_string_key(&parseState, "ldapbindpasswd");
+			push_jsonb_string_value(&parseState, hba->ldapbindpasswd);
+		}
+
+		if (hba->ldapsearchattribute)
+		{
+			push_jsonb_string_key(&parseState, "ldapsearchattribute");
+			push_jsonb_string_value(&parseState, hba->ldapsearchattribute);
+		}
+
+		if (hba->ldapscope)
+		{
+			push_jsonb_string_key(&parseState, "ldapscope");
+			push_jsonb_int32_value(&parseState, hba->ldapscope);
+		}
+	}
+
+	if (hba->auth_method == uaRADIUS)
+	{
+		if (hba->radiusserver)
+		{
+			push_jsonb_string_key(&parseState, "radiusserver");
+			push_jsonb_string_value(&parseState, hba->radiusserver);
+		}
+
+		if (hba->radiussecret)
+		{
+			push_jsonb_string_key(&parseState, "radiussecret");
+			push_jsonb_string_value(&parseState, hba->radiussecret);
+		}
+
+		if (hba->radiusidentifier)
+		{
+			push_jsonb_string_key(&parseState, "radiusidentifier");
+			push_jsonb_string_value(&parseState, hba->radiusidentifier);
+		}
+
+		if (hba->radiusport)
+		{
+			push_jsonb_string_key(&parseState, "radiusport");
+			push_jsonb_int32_value(&parseState, hba->radiusport);
+		}
+	}
+
+	result = pushJsonbValue(&parseState, WJB_END_OBJECT, NULL);
+	return JsonbValueToJsonb(result);
+}
+
+static bool
+token_is_a_database_keyword(HbaToken *tok)
+{
+	if (token_is_keyword(tok, "replication")
+		|| token_is_keyword(tok, "all")
+		|| token_is_keyword(tok, "sameuser")
+		|| token_is_keyword(tok, "samegroup")
+		|| token_is_keyword(tok, "samerole"))
+		return true;
+	return false;
+}
+
+#define NUM_PG_HBA_LOOKUP_ATTS	 13
+
+static void
+lookup_hba_line_callback(void *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;
+	MemoryContext old_cxt;
+	LookupHbaLineCxt *mycxt;
+
+	mycxt = (LookupHbaLineCxt *) context;
+
+	index = 0;
+	memset(values, 0, sizeof(values));
+	memset(nulls, 0, sizeof(nulls));
+
+	old_cxt = MemoryContextSwitchTo(mycxt->memcxt);
+
+	/* line_number */
+	values[index] = Int32GetDatum(lineno);
+
+	if (err_msg)
+	{
+		/* type */
+		index++;
+		nulls[index] = true;
+
+		/* keyword_database */
+		index++;
+		nulls[index] = true;
+
+		/* database */
+		index++;
+		nulls[index] = true;
+
+		/* keyword_user */
+		index++;
+		nulls[index] = true;
+
+		/* user */
+		index++;
+		nulls[index] = true;
+
+		/* keyword_address */
+		index++;
+		nulls[index] = true;
+
+		/* address */
+		index++;
+		nulls[index] = true;
+
+		/* netmask */
+		index++;
+		nulls[index] = true;
+
+		/* hostname */
+		index++;
+		nulls[index] = true;
+
+		/* method */
+		index++;
+		nulls[index] = true;
+
+		/* options */
+		index++;
+		nulls[index] = true;
+
+		/* error */
+		index++;
+		values[index] = 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");
+				break;
+		}
+
+		/* keyword_database and database */
+		index++;
+		if (list_length(hba->databases) != 0)
+		{
+			List	   *names = NULL;
+			List	   *keyword_names = NULL;
+			HbaToken   *tok;
+
+			foreach(dbcell, hba->databases)
+			{
+				tok = lfirst(dbcell);
+				if (token_is_a_database_keyword(tok))
+					keyword_names = lappend(keyword_names, tok->string);
+				else
+					names = lappend(names, tok->string);
+			}
+
+			/* keyword_database */
+			if (keyword_names != NULL)
+				values[index] = PointerGetDatum(strlist_to_textarray(keyword_names));
+			else
+				nulls[index] = true;
+
+			/* database */
+			index++;
+			if (names != NULL)
+				values[index] = PointerGetDatum(strlist_to_textarray(names));
+			else
+				nulls[index] = true;
+		}
+		else
+		{
+			nulls[index] = true;
+			index++;
+			nulls[index] = true;
+		}
+
+		/* keyword_user and user */
+		index++;
+		if (list_length(hba->roles) != 0)
+		{
+			List	   *roles = NULL;
+			List	   *keyword_roles = NULL;
+			HbaToken   *tok;
+
+			foreach(dbcell, hba->roles)
+			{
+				tok = lfirst(dbcell);
+				if (token_is_keyword(tok, "all"))
+					keyword_roles = lappend(keyword_roles, tok->string);
+				else
+					roles = lappend(roles, tok->string);
+			}
+
+			/* keyword_user */
+			if (keyword_roles != NULL)
+				values[index] = PointerGetDatum(strlist_to_textarray(keyword_roles));
+			else
+				nulls[index] = true;
+
+			/* user */
+			index++;
+			if (roles != NULL)
+				values[index] = PointerGetDatum(strlist_to_textarray(roles));
+			else
+				nulls[index] = true;
+		}
+		else
+		{
+			nulls[index] = true;
+			index++;
+			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++;
+		values[index] = PointerGetDatum(gethba_options(hba));
+
+		/* error */
+		index++;
+		nulls[index] = true;
+	}
+
+	tuple = heap_form_tuple(mycxt->tupdesc, values, nulls);
+	tuplestore_puttuple(mycxt->tuple_store, tuple);
+
+	MemoryContextSwitchTo(old_cxt);
+	return;
+}
+
+
+/*
+ * SQL-accessible SRF to return all the settings from the pg_hba.conf
+ * file.
+ */
+Datum
+hba_file_settings(PG_FUNCTION_ARGS)
+{
+	Tuplestorestate *tuple_store;
+	TupleDesc	tupdesc;
+	MemoryContext old_cxt;
+	LookupHbaLineCxt *mycxt;
+	ReturnSetInfo *rsi;
+
+	if (!superuser())
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 (errmsg("must be superuser to view pg_hba.conf settings"))));
+
+	/*
+	 * 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;
+
+	if (!rsi || !IsA(rsi, ReturnSetInfo) ||
+		(rsi->allowedModes & SFRM_Materialize) == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("set-valued function called in context that cannot accept a set")));
+
+	rsi->returnMode = SFRM_Materialize;
+
+	/*
+	 * Create the tupledesc and tuplestore in the per_query context as
+	 * required for SFRM_Materialize.
+	 */
+	old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+
+	tupdesc = CreateTemplateTupleDesc(NUM_PG_HBA_LOOKUP_ATTS, false);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "line_number",
+					   INT4OID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "type",
+					   TEXTOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "keyword_database",
+					   TEXTARRAYOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "database",
+					   TEXTARRAYOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "keyword_user",
+					   TEXTARRAYOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 6, "user_name",
+					   TEXTARRAYOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 7, "keyword_address",
+					   TEXTOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 8, "address",
+					   INETOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 9, "netmask",
+					   INETOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 10, "hostname",
+					   TEXTOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 11, "method",
+					   TEXTOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 12, "options",
+					   JSONBOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 13, "error",
+					   TEXTOID, -1, 0);
+	BlessTupleDesc(tupdesc);
+
+	tuple_store =
+		tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
+							  false, work_mem);
+
+	MemoryContextSwitchTo(old_cxt);
+
+	mycxt = (LookupHbaLineCxt *) palloc(sizeof(LookupHbaLineCxt));
+	mycxt->memcxt = AllocSetContextCreate(CurrentMemoryContext,
+										  "pg_hba_lookup tuple cxt",
+										  ALLOCSET_DEFAULT_MINSIZE,
+										  ALLOCSET_DEFAULT_INITSIZE,
+										  ALLOCSET_DEFAULT_MAXSIZE);
+	mycxt->tupdesc = tupdesc;
+	mycxt->tuple_store = tuple_store;
+
+	if (!load_hba(lookup_hba_line_callback, mycxt))
+		ereport(ERROR,
+				(errmsg("failed to load pg_hba.conf file"),
+			   errhint("more details may be available in the server log.")));
+
+	MemoryContextDelete(mycxt->memcxt);
+	pfree(mycxt);
+
+	rsi->setDesc = tupdesc;
+	rsi->setResult = tuple_store;
+
+	PG_RETURN_NULL();
+}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index f5c8e9d..579ee59 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1243,7 +1243,7 @@ PostmasterMain(int argc, char *argv[])
 	/*
 	 * Load configuration files for client authentication.
 	 */
-	if (!load_hba())
+	if (!load_hba(NULL, NULL))
 	{
 		/*
 		 * It makes no sense to continue if we fail to load the HBA file,
@@ -2494,7 +2494,7 @@ SIGHUP_handler(SIGNAL_ARGS)
 			signal_child(PgStatPID, SIGHUP);
 
 		/* Reload authentication config files too */
-		if (!load_hba())
+		if (!load_hba(NULL, NULL))
 			ereport(WARNING,
 					(errmsg("pg_hba.conf not reloaded")));
 
diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c
index ddc34ce..ad79cba 100644
--- a/src/backend/utils/adt/jsonb_util.c
+++ b/src/backend/utils/adt/jsonb_util.c
@@ -1802,3 +1802,50 @@ uniqueifyJsonbObject(JsonbValue *object)
 		object->val.object.nPairs = res + 1 - object->val.object.pairs;
 	}
 }
+
+
+void
+push_jsonb_string_key(JsonbParseState **pstate, char *string_key)
+{
+	JsonbValue	jb;
+
+	jb.type = jbvString;
+	jb.val.string.len = strlen(string_key);
+	jb.val.string.val = pstrdup(string_key);
+	pushJsonbValue(pstate, WJB_KEY, &jb);
+}
+
+void
+push_jsonb_bool_value(JsonbParseState **pstate, bool bool_val)
+{
+	JsonbValue	jb;
+
+	jb.type = jbvBool;
+	jb.val.boolean = bool_val;
+
+	pushJsonbValue(pstate, WJB_VALUE, &jb);
+}
+
+void
+push_jsonb_int32_value(JsonbParseState **pstate, int32 int32_val)
+{
+	JsonbValue	jb;
+	char		outputstr[64];
+
+	snprintf(outputstr, 64, "%d", int32_val);
+	jb.type = jbvNumeric;
+	jb.val.numeric = DatumGetNumeric(DirectFunctionCall3(numeric_in, CStringGetDatum(outputstr), 0, -1));
+
+	pushJsonbValue(pstate, WJB_VALUE, &jb);
+}
+
+void
+push_jsonb_string_value(JsonbParseState **pstate, char *string_value)
+{
+	JsonbValue	jb;
+
+	jb.type = jbvString;
+	jb.val.string.len = strlen(string_value);
+	jb.val.string.val = pstrdup(string_value);
+	pushJsonbValue(pstate, WJB_VALUE, &jb);
+}
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index d171972..19446bd 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -192,19 +192,6 @@ PerformAuthentication(Port *port)
 	 * FIXME: [fork/exec] Ugh.  Is there a way around this overhead?
 	 */
 #ifdef EXEC_BACKEND
-
-	/*
-	 * load_hba() and load_ident() want to work within the PostmasterContext,
-	 * so create that if it doesn't exist (which it won't).  We'll delete it
-	 * again later, in PostgresMain.
-	 */
-	if (PostmasterContext == NULL)
-		PostmasterContext = AllocSetContextCreate(TopMemoryContext,
-												  "Postmaster",
-												  ALLOCSET_DEFAULT_MINSIZE,
-												  ALLOCSET_DEFAULT_INITSIZE,
-												  ALLOCSET_DEFAULT_MAXSIZE);
-
 	if (!load_hba())
 	{
 		/*
@@ -739,6 +726,14 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		am_superuser = superuser();
 	}
 
+ 	/*
+	 * We don't need the HBA and ident data going forward, but we can't rely
+	 * on release of PostmasterContext to clean that up, so discard them
+	 * explicitly here.
+	 */
+	discard_hba();
+	discard_ident();
+
 	/*
 	 * If we're trying to shut down, only superusers can connect, and new
 	 * replication connections are not allowed.
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index af19c1a..37fdda1 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3053,6 +3053,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_file_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{23,25,1009,1009,1009,1009,25,869,869,25,25,3802,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{line_number,type,keyword_database,database,keyword_user,user_name,keyword_address,address,netmask,hostname,method,options,error}" _null_ _null_ hba_file_settings _null_ _null_ _null_ ));
+DESCR("show pg_hba config file settings");
 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/libpq/hba.h b/src/include/libpq/hba.h
index dc7d257..0b09f1a 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -100,8 +100,20 @@ typedef struct IdentLine
 /* kluge to avoid including libpq/libpq-be.h here */
 typedef struct Port hbaPort;
 
-extern bool load_hba(void);
+/*
+ * Optional callback function type for load_hba() function.
+ * Currently, valid callback function is passed to load_hba()
+ * by pg_hba_file_settings function view to frame the hba tuple.
+ */
+typedef void (*hba_line_callback) (void *context, int line_num,
+		HbaLine *hba_line, const char *err_msg);
+
+extern bool load_hba(hba_line_callback callback, void *callback_context);
 extern bool load_ident(void);
+
+extern void discard_hba(void);
+extern void discard_ident(void);
+
 extern void hba_getauthmethod(hbaPort *port);
 extern int check_usermap(const char *usermap_name,
 			  const char *pg_role, const char *auth_user,
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index a91be98..9a1f446 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1188,6 +1188,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_file_settings(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/include/utils/jsonb.h b/src/include/utils/jsonb.h
index fa52afc..5d51211 100644
--- a/src/include/utils/jsonb.h
+++ b/src/include/utils/jsonb.h
@@ -430,6 +430,12 @@ extern bool JsonbDeepContains(JsonbIterator **val,
 				  JsonbIterator **mContained);
 extern void JsonbHashScalarValue(const JsonbValue *scalarVal, uint32 *hash);
 
+/* jsonb_util.c support functions */
+void push_jsonb_string_key(JsonbParseState **pstate, char *string_key);
+void push_jsonb_bool_value(JsonbParseState **pstate, bool bool_val);
+void push_jsonb_int32_value(JsonbParseState **pstate, int32 int32_val);
+void push_jsonb_string_value(JsonbParseState **pstate, char *string_value);
+
 /* jsonb.c support functions */
 extern char *JsonbToCString(StringInfo out, JsonbContainer *in,
 			   int estimated_len);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 0c61fc2..93515d5 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1113,6 +1113,7 @@ LogicalOutputPluginWriterWrite
 LogicalRewriteMappingData
 LogicalTape
 LogicalTapeSet
+LookupHbaLineCxt
 MAGIC
 MBuf
 MEMORY_BASIC_INFORMATION
