diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 39f58c4..0595d1c 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2105,12 +2105,34 @@ Tue Oct 26 21:40:57 CEST 1999
 
 
       <varlistentry>
-        <term><literal>\g [ <replaceable class="parameter">filename</replaceable> ]</literal></term>
-        <term><literal>\g [ |<replaceable class="parameter">command</replaceable> ]</literal></term>
+        <term><literal>\g [ (<replaceable class="parameter">option</replaceable>=<replaceable class="parameter">value</replaceable> [...]) ] [ <replaceable class="parameter">filename</replaceable> ]</literal></term>
+        <term><literal>\g [ (<replaceable class="parameter">option</replaceable>=<replaceable class="parameter">value</replaceable> [...]) ] [ |<replaceable class="parameter">command</replaceable> ]</literal></term>
         <listitem>
         <para>
         Sends the current query buffer to the server for execution.
-        If an argument is given, the query's output is written to the named
+        </para>
+        <para>
+        If parentheses appear after <literal>\g</literal>, they surround a
+        space-separated list
+        of <replaceable class="parameter">option</replaceable><literal>=</literal><replaceable class="parameter">value</replaceable>
+        formatting-option clauses, which are interpreted in the same way
+        as <literal>\pset</literal>
+        <replaceable class="parameter">option</replaceable>
+        <replaceable class="parameter">value</replaceable> commands, but take
+        effect only for the duration of this query.  In this list, spaces are
+        not allowed around <literal>=</literal> signs, but are required
+        between option clauses.
+        If <literal>=</literal><replaceable class="parameter">value</replaceable>
+        is omitted, the
+        named <replaceable class="parameter">option</replaceable> is changed
+        in the same way as for
+        <literal>\pset</literal> <replaceable class="parameter">option</replaceable>
+        with no explicit <replaceable class="parameter">value</replaceable>.
+        </para>
+        <para>
+        If a <replaceable class="parameter">filename</replaceable>
+        or <literal>|</literal><replaceable class="parameter">command</replaceable>
+        argument is given, the query's output is written to the named
         file or piped to the given shell command, instead of displaying it as
         usual.  The file or command is written to only if the query
         successfully returns zero or more tuples, not if the query fails or
@@ -2119,13 +2141,15 @@ Tue Oct 26 21:40:57 CEST 1999
         <para>
         If the current query buffer is empty, the most recently sent query is
         re-executed instead.  Except for that behavior, <literal>\g</literal>
-        without an argument is essentially equivalent to a semicolon.
-        A <literal>\g</literal> with argument is a <quote>one-shot</quote>
-        alternative to the <command>\o</command> command.
+        without any arguments is essentially equivalent to a semicolon.
+        With arguments, <literal>\g</literal> provides
+        a <quote>one-shot</quote> alternative to the <command>\o</command>
+        command, and additionally allows one-shot adjustments of the
+        output formatting options normally set by <literal>\pset</literal>.
         </para>
         <para>
-        If the argument begins with <literal>|</literal>, then the entire remainder
-        of the line is taken to be
+        When the last argument begins with <literal>|</literal>, the entire
+        remainder of the line is taken to be
         the <replaceable class="parameter">command</replaceable> to execute,
         and neither variable interpolation nor backquote expansion are
         performed in it.  The rest of the line is simply passed literally to
@@ -2246,12 +2270,14 @@ hello 10
 
 
       <varlistentry>
-        <term><literal>\gx [ <replaceable class="parameter">filename</replaceable> ]</literal></term>
-        <term><literal>\gx [ |<replaceable class="parameter">command</replaceable> ]</literal></term>
+        <term><literal>\gx [ (<replaceable class="parameter">option</replaceable>=<replaceable class="parameter">value</replaceable> [...]) ] [ <replaceable class="parameter">filename</replaceable> ]</literal></term>
+        <term><literal>\gx [ (<replaceable class="parameter">option</replaceable>=<replaceable class="parameter">value</replaceable> [...]) ] [ |<replaceable class="parameter">command</replaceable> ]</literal></term>
         <listitem>
         <para>
-        <literal>\gx</literal> is equivalent to <literal>\g</literal>, but
-        forces expanded output mode for this query.  See <literal>\x</literal>.
+        <literal>\gx</literal> is equivalent to <literal>\g</literal>, except
+        that it forces expanded output mode for this query, as
+        if <literal>expanded=on</literal> were included in the list of
+        <literal>\pset</literal> options.  See also <literal>\x</literal>.
         </para>
         </listitem>
       </varlistentry>
@@ -4879,9 +4905,31 @@ second | three
 -[ RECORD 4 ]-
 first  | 4
 second | four
-</programlisting></para>
+</programlisting>
+  </para>
+
+  <para>
+  Also, these output format options can be set for just one query by using
+  <literal>\g</literal>:
+<programlisting>
+peter@localhost testdb=&gt; <userinput>SELECT * FROM my_table</userinput>
+peter@localhost testdb-&gt; <userinput>\g (format=aligned tuples_only=off expanded=on)</userinput>
+-[ RECORD 1 ]-
+first  | 1
+second | one
+-[ RECORD 2 ]-
+first  | 2
+second | two
+-[ RECORD 3 ]-
+first  | 3
+second | three
+-[ RECORD 4 ]-
+first  | 4
+second | four
+</programlisting>
+  </para>
 
-<para>
+  <para>
   When suitable, query results can be shown in a crosstab representation
   with the <command>\crosstabview</command> command:
 <programlisting>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 1055af5..a5160f9 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -86,6 +86,10 @@ static backslashResult exec_command_errverbose(PsqlScanState scan_state, bool ac
 static backslashResult exec_command_f(PsqlScanState scan_state, bool active_branch);
 static backslashResult exec_command_g(PsqlScanState scan_state, bool active_branch,
 									  const char *cmd);
+static backslashResult process_command_g_options(char *first_option,
+												 PsqlScanState scan_state,
+												 bool active_branch,
+												 const char *cmd);
 static backslashResult exec_command_gdesc(PsqlScanState scan_state, bool active_branch);
 static backslashResult exec_command_gexec(PsqlScanState scan_state, bool active_branch);
 static backslashResult exec_command_gset(PsqlScanState scan_state, bool active_branch);
@@ -1280,19 +1284,40 @@ exec_command_f(PsqlScanState scan_state, bool active_branch)
 }
 
 /*
- * \g [filename] -- send query, optionally with output to file/pipe
- * \gx [filename] -- same as \g, with expanded mode forced
+ * \g  [(pset-option[=pset-value] ...)] [filename/shell-command]
+ * \gx [(pset-option[=pset-value] ...)] [filename/shell-command]
+ *
+ * Send the current query.  If pset options are specified, they are made
+ * active just for this query.  If a filename or pipe command is given,
+ * the query output goes there.  \gx implicitly sets "expanded=on" along
+ * with any other pset options that are specified.
  */
 static backslashResult
 exec_command_g(PsqlScanState scan_state, bool active_branch, const char *cmd)
 {
 	backslashResult status = PSQL_CMD_SKIP_LINE;
+	char	   *fname;
 
-	if (active_branch)
+	/*
+	 * Because the option processing for this is fairly complicated, we do it
+	 * and then decide whether the branch is active.
+	 */
+	fname = psql_scan_slash_option(scan_state,
+								   OT_FILEPIPE, NULL, false);
+
+	if (fname && fname[0] == '(')
 	{
-		char	   *fname = psql_scan_slash_option(scan_state,
-												   OT_FILEPIPE, NULL, false);
+		/* Consume pset options through trailing ')' ... */
+		status = process_command_g_options(fname + 1, scan_state,
+										   active_branch, cmd);
+		free(fname);
+		/* ... and again attempt to scan the filename. */
+		fname = psql_scan_slash_option(scan_state,
+									   OT_FILEPIPE, NULL, false);
+	}
 
+	if (status == PSQL_CMD_SKIP_LINE && active_branch)
+	{
 		if (!fname)
 			pset.gfname = NULL;
 		else
@@ -1300,22 +1325,99 @@ exec_command_g(PsqlScanState scan_state, bool active_branch, const char *cmd)
 			expand_tilde(&fname);
 			pset.gfname = pg_strdup(fname);
 		}
-		free(fname);
 		if (strcmp(cmd, "gx") == 0)
 		{
-			/* save settings, then force expanded = 1 */
-			pset.gsavepopt = savePsetInfo(&pset.popt);
+			/* save settings if not done already, then force expanded=on */
+			if (pset.gsavepopt == NULL)
+				pset.gsavepopt = savePsetInfo(&pset.popt);
 			pset.popt.topt.expanded = 1;
 		}
 		status = PSQL_CMD_SEND;
 	}
-	else
-		ignore_slash_filepipe(scan_state);
+
+	free(fname);
 
 	return status;
 }
 
 /*
+ * Process parenthesized pset options for \g
+ *
+ * Note: okay to modify first_option, but not to free it; caller does that
+ */
+static backslashResult
+process_command_g_options(char *first_option, PsqlScanState scan_state,
+						  bool active_branch, const char *cmd)
+{
+	bool		success = true;
+	bool		found_r_paren = false;
+
+	do
+	{
+		char	   *option;
+		size_t		optlen;
+
+		/* If not first time through, collect a new option */
+		if (first_option)
+			option = first_option;
+		else
+		{
+			option = psql_scan_slash_option(scan_state,
+											OT_NORMAL, NULL, false);
+			if (!option)
+			{
+				if (active_branch)
+				{
+					pg_log_error("\\%s: missing right parenthesis", cmd);
+					success = false;
+				}
+				break;
+			}
+		}
+
+		/* Check for terminating right paren, and remove it from string */
+		optlen = strlen(option);
+		if (optlen > 0 && option[optlen - 1] == ')')
+		{
+			option[--optlen] = '\0';
+			found_r_paren = true;
+		}
+
+		/* If there was anything besides parentheses, parse/execute it */
+		if (optlen > 0)
+		{
+			/* We can have either "name" or "name=value" */
+			char	   *valptr = strchr(option, '=');
+
+			if (valptr)
+				*valptr++ = '\0';
+			if (active_branch)
+			{
+				/* save settings if not done already, then apply option */
+				if (pset.gsavepopt == NULL)
+					pset.gsavepopt = savePsetInfo(&pset.popt);
+				success &= do_pset(option, valptr, &pset.popt, true);
+			}
+		}
+
+		/* Clean up after this option.  We should not free first_option. */
+		if (first_option)
+			first_option = NULL;
+		else
+			free(option);
+	} while (!found_r_paren);
+
+	/* If we failed after already changing some options, undo side-effects */
+	if (!success && active_branch && pset.gsavepopt)
+	{
+		restorePsetInfo(&pset.popt, pset.gsavepopt);
+		pset.gsavepopt = NULL;
+	}
+
+	return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
+}
+
+/*
  * \gdesc -- describe query result
  */
 static backslashResult
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 9a18cb3..e750948 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -68,7 +68,7 @@ usage(unsigned short int pager)
 	 * Keep this line count in sync with the number of lines printed below!
 	 * Use "psql --help=options | wc" to count correctly.
 	 */
-	output = PageOutput(62, pager ? &(pset.popt.topt) : NULL);
+	output = PageOutput(63, pager ? &(pset.popt.topt) : NULL);
 
 	fprintf(output, _("psql is the PostgreSQL interactive terminal.\n\n"));
 	fprintf(output, _("Usage:\n"));
@@ -169,17 +169,18 @@ slashUsage(unsigned short int pager)
 	 * Use "psql --help=commands | wc" to count correctly.  It's okay to count
 	 * the USE_READLINE line even in builds without that.
 	 */
-	output = PageOutput(128, pager ? &(pset.popt.topt) : NULL);
+	output = PageOutput(133, pager ? &(pset.popt.topt) : NULL);
 
 	fprintf(output, _("General\n"));
 	fprintf(output, _("  \\copyright             show PostgreSQL usage and distribution terms\n"));
 	fprintf(output, _("  \\crosstabview [COLUMNS] execute query and display results in crosstab\n"));
 	fprintf(output, _("  \\errverbose            show most recent error message at maximum verbosity\n"));
-	fprintf(output, _("  \\g [FILE] or ;         execute query (and send results to file or |pipe)\n"));
+	fprintf(output, _("  \\g [(OPTIONS)] [FILE]  execute query (and send results to file or |pipe);\n"));
+	fprintf(output, _("                         \\g with no arguments is equivalent to a semicolon\n"));
 	fprintf(output, _("  \\gdesc                 describe result of query, without executing it\n"));
 	fprintf(output, _("  \\gexec                 execute query, then execute each value in its result\n"));
 	fprintf(output, _("  \\gset [PREFIX]         execute query and store results in psql variables\n"));
-	fprintf(output, _("  \\gx [FILE]             as \\g, but forces expanded output mode\n"));
+	fprintf(output, _("  \\gx [(OPTIONS)] [FILE] as \\g, but forces expanded output mode\n"));
 	fprintf(output, _("  \\q                     quit psql\n"));
 	fprintf(output, _("  \\watch [SEC]           execute query every SEC seconds\n"));
 	fprintf(output, "\n");
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 2423ae2..0b990fd 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -76,6 +76,28 @@ four  | 4
 (1 row)
 
 \unset FETCH_COUNT
+-- \g/\gx with pset options
+SELECT 1 as one, 2 as two \g (format=csv csv_fieldsep='\t')
+one	two
+1	2
+\g
+ one | two 
+-----+-----
+   1 |   2
+(1 row)
+
+SELECT 1 as one, 2 as two \gx (title='foo bar')
+foo bar
+-[ RECORD 1 ]
+one | 1
+two | 2
+
+\g
+ one | two 
+-----+-----
+   1 |   2
+(1 row)
+
 -- \gset
 select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
 \echo :pref01_test01 :pref01_test02 :pref01_test03
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index 3c876d2..d462c35 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -38,6 +38,13 @@ SELECT 3 as three, 4 as four \gx
 
 \unset FETCH_COUNT
 
+-- \g/\gx with pset options
+
+SELECT 1 as one, 2 as two \g (format=csv csv_fieldsep='\t')
+\g
+SELECT 1 as one, 2 as two \gx (title='foo bar')
+\g
+
 -- \gset
 
 select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
