diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 4b79958b35757b3acd6ef4e11c04de9631b878a0..2756652be2129ae158383c3d3470bd572131fbb1 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7559,6 +7559,11 @@
       <entry>parameter settings</entry>
      </row>
 
+     <row>
+      <entry><link linkend="view-pg-file-settings"><structname>pg_file_settings</structname></link></entry>
+      <entry>file location of parameter settings</entry>
+     </row>
+
      <row>
       <entry><link linkend="view-pg-shadow"><structname>pg_shadow</structname></link></entry>
       <entry>database users</entry>
@@ -9173,6 +9178,79 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
 
  </sect1>
 
+ <sect1 id="view-pg-file-settings">
+  <title><structname>pg_file_settings</structname></title>
+
+  <indexterm zone="view-pg-file-settings">
+   <primary>pg_file_settings</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_file_settings</structname> provides the file
+   name, line number and value of all parameters which are set through
+   configuration files.
+   In contrast to <structname>pg_settings</structname>, a row is provided for
+   each occurrence of the parameter across all configuration files. This is helpful
+   for discovering why one value may have been used in preference to another
+   when the parameters were loaded.
+  </para>
+
+  <table>
+   <title><structname>pg_file_settings</> Columns</title>
+
+  <tgroup cols="3">
+   <thead>
+    <row>
+     <entry>Name</entry>
+     <entry>Type</entry>
+     <entry>Description</entry>
+    </row>
+   </thead>
+   <tbody>
+    <row>
+     <entry><structfield>sourcefile</structfield></entry>
+     <entry><structfield>text</structfield></entry>
+     <entry>Path to and name of the configration file</entry>
+    </row>
+    <row>
+     <entry><structfield>sourceline</structfield></entry>
+     <entry><structfield>integer</structfield></entry>
+     <entry>
+      Line number within the configuration file where the value was set
+     </entry>
+    </row>
+    <row>
+     <entry><structfield>seqno</structfield></entry>
+     <entry><structfield>integer</structfield></entry>
+     <entry>Order in which the setting was loaded</entry>
+    </row>
+    <row>
+     <entry><structfield>name</structfield></entry>
+     <entry><structfield>text</structfield></entry>
+     <entry>Run-time configuration parameter name</entry>
+    </row>
+    <row>
+     <entry><structfield>setting</structfield></entry>
+     <entry><structfield>text</structfield></entry>
+     <entry>value of the parameter</entry>
+    </row>
+   </tbody>
+  </tgroup>
+ </table>
+
+  <para>
+   See <xref linkend="config-setting"> for more information about the various
+   ways to change these parameters.
+  </para>
+
+  <para>
+   The <structname>pg_file_settings</structname> view cannot be modified
+   directly as it represents information, as read in at server start or
+   reload time, about all parameter settings across all configuration files.
+  </para>
+
+</sect1>
+
  <sect1 id="view-pg-shadow">
   <title><structname>pg_shadow</structname></title>
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2ad01f4cb41e28ddf106cb1ef396a351e9d2bbe5..18921c4bc52aba0ebf11346b3790d7978e7b8d45 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -411,6 +411,12 @@ CREATE RULE pg_settings_n AS
 
 GRANT SELECT, UPDATE ON pg_settings TO PUBLIC;
 
+CREATE VIEW pg_file_settings AS
+   SELECT * FROM pg_show_all_file_settings() AS A;
+
+REVOKE ALL on pg_file_settings FROM PUBLIC;
+REVOKE EXECUTE ON FUNCTION pg_show_all_file_settings() FROM PUBLIC;
+
 CREATE VIEW pg_timezone_abbrevs AS
     SELECT * FROM pg_timezone_abbrevs();
 
diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index c5e0fac4671312904acf12c7c23c2b7c9ad61469..a04d35d3c988a26a0336599c0c8aae26f48706c0 100644
--- a/src/backend/utils/misc/guc-file.l
+++ b/src/backend/utils/misc/guc-file.l
@@ -120,6 +120,7 @@ ProcessConfigFile(GucContext context)
 			   *head,
 			   *tail;
 	int			i;
+	int			file_variables_count = 0;
 
 	/*
 	 * Config files are processed on startup (by the postmaster only)
@@ -255,6 +256,7 @@ ProcessConfigFile(GucContext context)
 			error = true;
 			ConfFileWithError = item->filename;
 		}
+		file_variables_count++;
 	}
 
 	/*
@@ -341,6 +343,54 @@ ProcessConfigFile(GucContext context)
 						PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT);
 	}
 
+	/*
+	 * Check if we have allocated the array yet.
+	 *
+	 * If not, allocate it based on the number of file variables we have seen.
+	 */
+	if (!guc_file_variables)
+	{
+		/* For the first call */
+		num_guc_file_variables = file_variables_count;
+		guc_file_variables = (ConfigFileVariable *) guc_malloc(FATAL,
+					num_guc_file_variables * sizeof(struct ConfigFileVariable));
+	}
+	else
+	{
+		int i;
+
+		/* Free all of the previously allocated entries */
+		for (i = 0; i < num_guc_file_variables; i++)
+		{
+			free(guc_file_variables[i].name);
+			free(guc_file_variables[i].value);
+			free(guc_file_variables[i].filename);
+		}
+
+		/* Update the global count and realloc based on the new size */
+		num_guc_file_variables = file_variables_count;
+		guc_file_variables = (ConfigFileVariable *) guc_realloc(FATAL,
+									guc_file_variables,
+					num_guc_file_variables * sizeof(struct ConfigFileVariable));
+	}
+
+	/*
+	 * Copy the settings which came from the files read into the
+	 * guc_file_variables array which backs the pg_show_file_settings()
+	 * function.
+	 */
+	for (item = head, i = 0; item && i < num_guc_file_variables;
+		 item = item->next, i++)
+	{
+		guc_file_variables[i].name = guc_strdup(FATAL, item->name);
+		guc_file_variables[i].value = guc_strdup(FATAL, item->value);
+		guc_file_variables[i].filename = guc_strdup(FATAL, item->filename);
+		guc_file_variables[i].sourceline = item->sourceline;
+	}
+
+	/* We had better have made it through the loop above to a clean ending. */
+	Assert(!item && i == num_guc_file_variables);
+
 	/*
 	 * Now apply the values from the config file.
 	 */
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 8727ee3b744b6d34eb2c128d994f21367b25bc93..5f71dedff341bca8b515a946c71ea2cb426f766f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3678,6 +3678,22 @@ static struct config_generic **guc_variables;
 /* Current number of variables contained in the vector */
 static int	num_guc_variables;
 
+/*
+ * Lookup of variables for pg_file_settings view.
+ * guc_file_variables is an array of length num_guc_file_variables.
+ */
+typedef struct ConfigFileVariable
+{
+	char	*name;
+	char	*value;
+	char	*filename;
+	int		sourceline;
+} ConfigFileVariable;
+static struct ConfigFileVariable *guc_file_variables;
+
+/* Number of file variables */
+static int	num_guc_file_variables;
+
 /* Vector capacity */
 static int	size_guc_variables;
 
@@ -8148,6 +8164,110 @@ show_all_settings(PG_FUNCTION_ARGS)
 	}
 }
 
+/*
+ * show_all_file_settings
+ *
+ * returns a table of all parameter settings in all configuration files
+ * which includes the config file path/name, filename, a sequence number
+ * indicating when we loaded it, the parameter name, and the value it is
+ * set to.
+ *
+ * Note: no filtering is done here, instead we depend on the GRANT system
+ * to prevent unprivileged users from accessing this function or the view
+ * built on top of it.
+ */
+Datum
+show_all_file_settings(PG_FUNCTION_ARGS)
+{
+#define NUM_PG_FILE_SETTINGS_ATTS 5
+	FuncCallContext *funcctx;
+	TupleDesc	tupdesc;
+	int			call_cntr;
+	int			max_calls;
+	AttInMetadata *attinmeta;
+	MemoryContext oldcontext;
+
+	if (SRF_IS_FIRSTCALL())
+	{
+		funcctx = SRF_FIRSTCALL_INIT();
+
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		/*
+		 * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns
+		 * of the appropriate types
+		 */
+
+		tupdesc = CreateTemplateTupleDesc(NUM_PG_FILE_SETTINGS_ATTS, false);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "sourcefile",
+						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "sourceline",
+						   INT4OID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "seqno",
+						   INT4OID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "name",
+						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "setting",
+						   TEXTOID, -1, 0);
+
+		attinmeta = TupleDescGetAttInMetadata(tupdesc);
+		funcctx->attinmeta = attinmeta;
+		funcctx->max_calls = num_guc_file_variables;
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	funcctx = SRF_PERCALL_SETUP();
+
+	call_cntr = funcctx->call_cntr;
+	max_calls = funcctx->max_calls;
+	attinmeta = funcctx->attinmeta;
+
+	if (call_cntr < max_calls)
+	{
+		char	   *values[NUM_PG_FILE_SETTINGS_ATTS];
+		HeapTuple	tuple;
+		Datum		result;
+		ConfigFileVariable conf;
+		char		buffer[12]; /* must be at least 12, per pg_ltoa */
+
+		/* Check to avoid going past end of array */
+		if (call_cntr > num_guc_file_variables)
+			SRF_RETURN_DONE(funcctx);
+
+		conf = guc_file_variables[call_cntr];
+
+		/* sourcefile */
+		values[0] = conf.filename;
+
+		/* sourceline */
+		pg_ltoa(conf.sourceline, buffer);
+		values[1] = pstrdup(buffer);
+
+		/* seqno */
+		pg_ltoa(call_cntr + 1, buffer);
+		values[2] = pstrdup(buffer);
+
+		/* name */
+		values[3] = conf.name;
+
+		/* setting */
+		values[4] = conf.value;
+
+		/* build a tuple */
+		tuple = BuildTupleFromCStrings(attinmeta, values);
+
+		/* make the tuple into a datum */
+		result = HeapTupleGetDatum(tuple);
+
+		SRF_RETURN_NEXT(funcctx, result);
+	}
+	else
+	{
+		SRF_RETURN_DONE(funcctx);
+	}
+
+}
+
 static char *
 _ShowOption(struct config_generic * record, bool use_units)
 {
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index bd67d727979dc17c0732331ff2e223bceaf6e1c4..76f9abf9fd183cbffd60633bcf54e53cbb2f9334 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3060,6 +3060,8 @@ DATA(insert OID = 2078 (  set_config		PGNSP PGUID 12 1 0 0 0 f f f f f f v 3 0 2
 DESCR("SET X as a function");
 DATA(insert OID = 2084 (  pg_show_all_settings	PGNSP PGUID 12 1 1000 0 0 f f f f t t s 0 0 2249 "" "{25,25,25,25,25,25,25,25,25,25,25,1009,25,25,25,23}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{name,setting,unit,category,short_desc,extra_desc,context,vartype,source,min_val,max_val,enumvals,boot_val,reset_val,sourcefile,sourceline}" _null_ _null_ show_all_settings _null_ _null_ _null_ ));
 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 s 0 0 2249 "" "{25,23,23,25,25}" "{o,o,o,o,o}" "{sourcefile,sourceline,seqno,name,setting}" _null_ _null_ show_all_file_settings _null_ _null_ _null_ ));
+DESCR("show config file settings");
 DATA(insert OID = 1371 (  pg_lock_status   PGNSP PGUID 12 1 1000 0 0 f f f f t t v 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 = 1065 (  pg_prepared_xact PGNSP PGUID 12 1 1000 0 0 f f f f t t v 0 0 2249 "" "{28,25,1184,26,26}" "{o,o,o,o,o}" "{transaction,gid,prepared,ownerid,dbid}" _null_ _null_ pg_prepared_xact _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index e8104f01a137e73c8971741a7329b722098ec9b1..926421d9969fe4945a2e72f3b3453c56c1d31a5e 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1100,6 +1100,7 @@ extern Datum quote_nullable(PG_FUNCTION_ARGS);
 extern Datum show_config_by_name(PG_FUNCTION_ARGS);
 extern Datum set_config_by_name(PG_FUNCTION_ARGS);
 extern Datum show_all_settings(PG_FUNCTION_ARGS);
+extern Datum show_all_file_settings(PG_FUNCTION_ARGS);
 
 /* lockfuncs.c */
 extern Datum pg_lock_status(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 2df24c0de16c821478005cf670db7692bb376d98..a379a7279c5dad46c00b197f813c6a1a2c589742 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1312,6 +1312,12 @@ pg_cursors| SELECT c.name,
     c.is_scrollable,
     c.creation_time
    FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
+pg_file_settings| SELECT a.sourcefile,
+    a.sourceline,
+    a.seqno,
+    a.name,
+    a.setting
+   FROM pg_show_all_file_settings() a(sourcefile, sourceline, seqno, name, setting);
 pg_group| SELECT pg_authid.rolname AS groname,
     pg_authid.oid AS grosysid,
     ARRAY( SELECT pg_auth_members.member