diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index a2694e548a..ca2769b02a 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -5308,6 +5308,141 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
 
      </variablelist>
     </sect2>
+
+    <sect2 id="runtime-config-query-explain">
+     <title>Default EXPLAIN options</title>
+
+     <variablelist>
+
+     <varlistentry id="guc-default-explain-analyze" xreflabel="default_explain_analyze">
+      <term><varname>default_explain_analyze</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_analyze</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>ANALYZE</command> option for <command>EXPLAIN</command>.
+		The default is off.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-buffers" xreflabel="default_explain_buffers">
+      <term><varname>default_explain_buffers</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_buffers</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>BUFFERS</command> option for <command>EXPLAIN</command>.
+		The default is off.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-cost" xreflabel="default_explain_cost">
+      <term><varname>default_explain_cost</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_cost</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>COST</command> option for <command>EXPLAIN</command>.
+		The default is on.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-format" xreflabel="default_explain_format">
+      <term><varname>default_explain_format</varname> (<type>text</type>)
+      <indexterm>
+       <primary><varname>default_explain_format</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>FORMAT</command> option for <command>EXPLAIN</command>.
+		The default is text.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-settings" xreflabel="default_explain_settings">
+      <term><varname>default_explain_settings</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_settings</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>SETTINGS</command> option for <command>EXPLAIN</command>.
+		The default is off.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-summary" xreflabel="default_explain_summary">
+      <term><varname>default_explain_summary</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_summary</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>SUMMARY</command> option for <command>EXPLAIN</command>.
+		The default is off.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-timing" xreflabel="default_explain_timing">
+      <term><varname>default_explain_timing</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_timing</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>TIMING</command> option for <command>EXPLAIN</command>.
+		The default is on.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-verbose" xreflabel="default_explain_verbose">
+      <term><varname>default_explain_verbose</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_verbose</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>VERBOSE</command> option for <command>EXPLAIN</command>.
+		The default is off.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-default-explain-wal" xreflabel="default_explain_wal">
+      <term><varname>default_explain_wal</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>default_explain_wal</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+	    Sets the default <command>WAL</command> option for <command>EXPLAIN</command>.
+		The default is off.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     </variablelist>
+    </sect2>
+
      <sect2 id="runtime-config-query-other">
      <title>Other Planner Options</title>
 
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index efd7201d61..974de580bb 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -17,6 +17,7 @@
 #include "catalog/pg_type.h"
 #include "commands/createas.h"
 #include "commands/defrem.h"
+#include "commands/explain.h"
 #include "commands/prepare.h"
 #include "executor/nodeHash.h"
 #include "foreign/fdwapi.h"
@@ -39,6 +40,26 @@
 #include "utils/typcache.h"
 #include "utils/xml.h"
 
+/*
+ *	User-tweakable parameters
+ */
+bool	default_explain_analyze = false;
+bool	default_explain_buffers = false;
+bool	default_explain_costs = true;
+int		default_explain_format = EXPLAIN_FORMAT_TEXT;
+bool	default_explain_settings = false;
+bool	default_explain_summary = false;
+bool	default_explain_timing = true;
+bool	default_explain_verbose = false;
+bool	default_explain_wal = false;
+
+const struct config_enum_entry explain_format_options[] = {
+	{"text", EXPLAIN_FORMAT_TEXT, false},
+	{"xml", EXPLAIN_FORMAT_XML, false},
+	{"json", EXPLAIN_FORMAT_JSON, false},
+	{"yaml", EXPLAIN_FORMAT_YAML, false},
+	{NULL, 0, false}
+};
 
 /* Hook for plugins to get control in ExplainOneQuery() */
 ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
@@ -164,8 +185,26 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt,
 	TupOutputState *tstate;
 	List	   *rewritten;
 	ListCell   *lc;
-	bool		timing_set = false;
-	bool		summary_set = false;
+	DefElem    *danalyze = NULL;
+	DefElem    *dbuffers = NULL;
+	DefElem    *dcosts = NULL;
+	DefElem    *dformat = NULL;
+	DefElem    *dsettings = NULL;
+	DefElem    *dsummary = NULL;
+	DefElem    *dtiming = NULL;
+	DefElem    *dverbose = NULL;
+	DefElem    *dwal = NULL;
+
+	/* Set defaults. */
+	es->analyze = default_explain_analyze;
+	es->buffers = default_explain_buffers;
+	es->costs = default_explain_costs;
+	es->format = default_explain_format;
+	es->settings = default_explain_settings;
+	es->summary = default_explain_summary;
+	es->timing = default_explain_timing;
+	es->verbose = default_explain_verbose;
+	es->wal = default_explain_wal;
 
 	/* Parse options list. */
 	foreach(lc, stmt->options)
@@ -173,30 +212,46 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt,
 		DefElem    *opt = (DefElem *) lfirst(lc);
 
 		if (strcmp(opt->defname, "analyze") == 0)
+		{
+			if (danalyze)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			danalyze = opt;
 			es->analyze = defGetBoolean(opt);
-		else if (strcmp(opt->defname, "verbose") == 0)
-			es->verbose = defGetBoolean(opt);
-		else if (strcmp(opt->defname, "costs") == 0)
-			es->costs = defGetBoolean(opt);
+		}
 		else if (strcmp(opt->defname, "buffers") == 0)
+		{
+			if (dbuffers)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dbuffers = opt;
 			es->buffers = defGetBoolean(opt);
-		else if (strcmp(opt->defname, "wal") == 0)
-			es->wal = defGetBoolean(opt);
-		else if (strcmp(opt->defname, "settings") == 0)
-			es->settings = defGetBoolean(opt);
-		else if (strcmp(opt->defname, "timing") == 0)
-		{
-			timing_set = true;
-			es->timing = defGetBoolean(opt);
 		}
-		else if (strcmp(opt->defname, "summary") == 0)
+		else if (strcmp(opt->defname, "costs") == 0)
 		{
-			summary_set = true;
-			es->summary = defGetBoolean(opt);
+			if (dcosts)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dcosts = opt;
+			es->costs = defGetBoolean(opt);
 		}
 		else if (strcmp(opt->defname, "format") == 0)
 		{
-			char	   *p = defGetString(opt);
+			char	   *p;
+
+			if (dformat)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dformat = opt;
+			p = defGetString(opt);
 
 			if (strcmp(p, "text") == 0)
 				es->format = EXPLAIN_FORMAT_TEXT;
@@ -213,6 +268,56 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt,
 								opt->defname, p),
 						 parser_errposition(pstate, opt->location)));
 		}
+		else if (strcmp(opt->defname, "settings") == 0)
+		{
+			if (dsettings)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dsettings = opt;
+			es->settings = defGetBoolean(opt);
+		}
+		else if (strcmp(opt->defname, "summary") == 0)
+		{
+			if (dsummary)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dsummary = opt;
+			es->summary = defGetBoolean(opt);
+		}
+		else if (strcmp(opt->defname, "timing") == 0)
+		{
+			if (dtiming)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dtiming = opt;
+			es->timing = defGetBoolean(opt);
+		}
+		else if (strcmp(opt->defname, "verbose") == 0)
+		{
+			if (dverbose)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dverbose = opt;
+			es->verbose = defGetBoolean(opt);
+		}
+		else if (strcmp(opt->defname, "wal") == 0)
+		{
+			if (dwal)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, opt->location)));
+			dwal = opt;
+			es->wal = defGetBoolean(opt);
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -221,27 +326,41 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt,
 					 parser_errposition(pstate, opt->location)));
 	}
 
+	/*
+	 * If ANALYZE wasn't explicitly set and isn't on by default, turn off some
+	 * settings that aren't also explicitly set.  This is so we can raise errors
+	 * on incompatible options.
+	 */
+	if (!danalyze && !es->analyze)
+	{
+		if (!dbuffers)
+			es->buffers = false;
+		if (!dtiming)
+			es->timing = false;
+		if (!dwal)
+			es->wal = false;
+	}
+
+	/* check that BUFFERS is used with EXPLAIN ANALYZE */
 	if (es->buffers && !es->analyze)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("EXPLAIN option BUFFERS requires ANALYZE")));
 
-	if (es->wal && !es->analyze)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("EXPLAIN option WAL requires ANALYZE")));
-
-	/* if the timing was not set explicitly, set default value */
-	es->timing = (timing_set) ? es->timing : es->analyze;
-
-	/* check that timing is used with EXPLAIN ANALYZE */
+	/* check that TIMING is used with EXPLAIN ANALYZE */
 	if (es->timing && !es->analyze)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("EXPLAIN option TIMING requires ANALYZE")));
 
-	/* if the summary was not set explicitly, set default value */
-	es->summary = (summary_set) ? es->summary : es->analyze;
+	/* check that WAL is used with EXPLAIN ANALYZE */
+	if (es->wal && !es->analyze)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("EXPLAIN option WAL requires ANALYZE")));
+
+	/* if SUMMARY was not set explicitly, set default value */
+	es->summary = (dsummary) ? es->summary : es->analyze;
 
 	/*
 	 * Parse analysis was done already, but we still have to run the rule
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 2f3e0a70e0..349946eb89 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -38,6 +38,7 @@
 #include "catalog/pg_authid.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/explain.h"
 #include "commands/prepare.h"
 #include "commands/trigger.h"
 #include "commands/user.h"
@@ -511,6 +512,7 @@ extern const struct config_enum_entry archive_mode_options[];
 extern const struct config_enum_entry recovery_target_action_options[];
 extern const struct config_enum_entry sync_method_options[];
 extern const struct config_enum_entry dynamic_shared_memory_options[];
+extern const struct config_enum_entry explain_format_options[];
 
 /*
  * GUC option variables that are exported from this module
@@ -725,6 +727,8 @@ const char *const config_group_names[] =
 	gettext_noop("Replication / Subscribers"),
 	/* QUERY_TUNING */
 	gettext_noop("Query Tuning"),
+	/* QUERY_TUNING_EXPLAIN */
+	gettext_noop("Query Tuning / EXPLAIN Options"),
 	/* QUERY_TUNING_METHOD */
 	gettext_noop("Query Tuning / Planner Method Configuration"),
 	/* QUERY_TUNING_COST */
@@ -931,6 +935,78 @@ static const unit_conversion time_unit_conversion_table[] =
 
 static struct config_bool ConfigureNamesBool[] =
 {
+	{
+		{"default_explain_analyze", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default ANALYZE option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_analyze,
+		false,
+		NULL, NULL, NULL
+	},
+	{
+		{"default_explain_buffers", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default BUFFERS option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_buffers,
+		false,
+		NULL, NULL, NULL
+	},
+	{
+		{"default_explain_costs", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default COSTS option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_costs,
+		true,
+		NULL, NULL, NULL
+	},
+	{
+		{"default_explain_settings", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default SETTINGS option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_settings,
+		false,
+		NULL, NULL, NULL
+	},
+	{
+		{"default_explain_summary", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default SUMMARY option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_summary,
+		false,
+		NULL, NULL, NULL
+	},
+	{
+		{"default_explain_timing", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default TIMING option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_timing,
+		true,
+		NULL, NULL, NULL
+	},
+	{
+		{"default_explain_verbose", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default VERBOSE option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_verbose,
+		false,
+		NULL, NULL, NULL
+	},
+	{
+		{"default_explain_wal", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default WAL option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_wal,
+		false,
+		NULL, NULL, NULL
+	},
 	{
 		{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
 			gettext_noop("Enables the planner's use of sequential-scan plans."),
@@ -4490,6 +4566,16 @@ static struct config_enum ConfigureNamesEnum[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"default_explain_format", PGC_USERSET, QUERY_TUNING_EXPLAIN,
+			gettext_noop("Sets the default FORMAT option for EXPLAIN."),
+			NULL
+		},
+		&default_explain_format,
+		EXPLAIN_FORMAT_TEXT, explain_format_options,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"default_transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
 			gettext_noop("Sets the transaction isolation level of each new transaction."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 995b6ca155..3bcf399ba3 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -414,6 +414,18 @@
 #plan_cache_mode = auto			# auto, force_generic_plan or
 					# force_custom_plan
 
+# - EXPLAIN Options -
+
+#default_explain_analyze = off
+#default_explain_buffers = off
+#default_explain_costs = on
+#default_explain_format = text
+#default_explain_settings = off
+#default_explain_summary = off
+#default_explain_timing = on
+#default_explain_verbose = off
+#default_explain_wal = off
+
 
 #------------------------------------------------------------------------------
 # REPORTING AND LOGGING
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index ba661d32a6..9156f55920 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -124,4 +124,17 @@ extern void ExplainOpenGroup(const char *objtype, const char *labelname,
 extern void ExplainCloseGroup(const char *objtype, const char *labelname,
 							  bool labeled, ExplainState *es);
 
+/*
+ *	User-tweakable parameters
+ */
+extern PGDLLEXPORT bool	default_explain_analyze;
+extern PGDLLEXPORT bool	default_explain_buffers;
+extern PGDLLEXPORT bool	default_explain_costs;
+extern PGDLLEXPORT int	default_explain_format;
+extern PGDLLEXPORT bool	default_explain_settings;
+extern PGDLLEXPORT bool	default_explain_summary;
+extern PGDLLEXPORT bool	default_explain_timing;
+extern PGDLLEXPORT bool	default_explain_verbose;
+extern PGDLLEXPORT bool	default_explain_wal;
+
 #endif							/* EXPLAIN_H */
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 454c2df487..f31cfa7ddf 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -77,6 +77,7 @@ enum config_group
 	REPLICATION_STANDBY,
 	REPLICATION_SUBSCRIBERS,
 	QUERY_TUNING,
+	QUERY_TUNING_EXPLAIN,
 	QUERY_TUNING_METHOD,
 	QUERY_TUNING_COST,
 	QUERY_TUNING_GEQO,
