diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 385cb599278a4885ad93848ff1d33b3462fa288f..e8afc247afe04eaed53522ea2326e33733ffd6ba 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1717,6 +1717,20 @@ Tue Oct 26 21:40:57 CEST 1999
       </varlistentry>
 
 
+      <varlistentry>
+        <term><literal>\errverbose</literal></term>
+
+        <listitem>
+        <para>
+        Repeats the most recent server error message at maximum
+        verbosity, as though <varname>VERBOSITY</varname> were set
+        to <literal>verbose</> and <varname>SHOW_CONTEXT</varname> were
+        set to <literal>always</>.
+        </para>
+        </listitem>
+      </varlistentry>
+
+
       <varlistentry>
         <term><literal>\f [ <replaceable class="parameter">string</replaceable> ]</literal></term>
 
@@ -3244,6 +3258,8 @@ bar
         that context will be shown in error messages, but not in notice or
         warning messages).  This setting has no effect
         when <varname>VERBOSITY</> is set to <literal>terse</>.
+        (See also <command>\errverbose</>, for use when you want a verbose
+        version of the error you just got.)
         </para>
         </listitem>
       </varlistentry>
@@ -3286,6 +3302,8 @@ bar
         This variable can be set to the values <literal>default</>,
         <literal>verbose</>, or <literal>terse</> to control the verbosity
         of error reports.
+        (See also <command>\errverbose</>, for use when you want a verbose
+        version of the error you just got.)
         </para>
         </listitem>
       </varlistentry>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 50dc43bf61a45a7265368d330149d981443441cf..3401b5183b056bc2b8439e729bb2b0c16a91a060 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -822,6 +822,28 @@ exec_command(const char *cmd,
 		}
 	}
 
+	/* \errverbose -- display verbose message from last failed query */
+	else if (strcmp(cmd, "errverbose") == 0)
+	{
+		if (pset.last_error_result)
+		{
+			char	   *msg;
+
+			msg = PQresultVerboseErrorMessage(pset.last_error_result,
+											  PQERRORS_VERBOSE,
+											  PQSHOW_CONTEXT_ALWAYS);
+			if (msg)
+			{
+				psql_error("%s", msg);
+				PQfreemem(msg);
+			}
+			else
+				puts(_("out of memory"));
+		}
+		else
+			puts(_("There was no previous error."));
+	}
+
 	/* \f -- change field separator */
 	else if (strcmp(cmd, "f") == 0)
 	{
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 892058e9ac833645e583734ab6567a8ffb0bf055..a2a07fb538e8f0acfe606a6c78400e16a6ced0f5 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -497,6 +497,33 @@ AcceptResult(const PGresult *result)
 }
 
 
+/*
+ * ClearOrSaveResult
+ *
+ * If the result represents an error, remember it for possible display by
+ * \errverbose.  Otherwise, just PQclear() it.
+ */
+static void
+ClearOrSaveResult(PGresult *result)
+{
+	if (result)
+	{
+		switch (PQresultStatus(result))
+		{
+			case PGRES_NONFATAL_ERROR:
+			case PGRES_FATAL_ERROR:
+				if (pset.last_error_result)
+					PQclear(pset.last_error_result);
+				pset.last_error_result = result;
+				break;
+
+			default:
+				PQclear(result);
+				break;
+		}
+	}
+}
+
 
 /*
  * PSQLexec
@@ -548,7 +575,7 @@ PSQLexec(const char *query)
 
 	if (!AcceptResult(res))
 	{
-		PQclear(res);
+		ClearOrSaveResult(res);
 		res = NULL;
 	}
 
@@ -590,7 +617,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
 
 	if (!AcceptResult(res))
 	{
-		PQclear(res);
+		ClearOrSaveResult(res);
 		return 0;
 	}
 
@@ -1077,11 +1104,11 @@ SendQuery(const char *query)
 		if (PQresultStatus(results) != PGRES_COMMAND_OK)
 		{
 			psql_error("%s", PQerrorMessage(pset.db));
-			PQclear(results);
+			ClearOrSaveResult(results);
 			ResetCancelConn();
 			goto sendquery_cleanup;
 		}
-		PQclear(results);
+		ClearOrSaveResult(results);
 		transaction_status = PQtransactionStatus(pset.db);
 	}
 
@@ -1102,11 +1129,11 @@ SendQuery(const char *query)
 			if (PQresultStatus(results) != PGRES_COMMAND_OK)
 			{
 				psql_error("%s", PQerrorMessage(pset.db));
-				PQclear(results);
+				ClearOrSaveResult(results);
 				ResetCancelConn();
 				goto sendquery_cleanup;
 			}
-			PQclear(results);
+			ClearOrSaveResult(results);
 			on_error_rollback_savepoint = true;
 		}
 	}
@@ -1202,7 +1229,7 @@ SendQuery(const char *query)
 			if (PQresultStatus(svptres) != PGRES_COMMAND_OK)
 			{
 				psql_error("%s", PQerrorMessage(pset.db));
-				PQclear(svptres);
+				ClearOrSaveResult(svptres);
 				OK = false;
 
 				PQclear(results);
@@ -1213,7 +1240,7 @@ SendQuery(const char *query)
 		}
 	}
 
-	PQclear(results);
+	ClearOrSaveResult(results);
 
 	/* Possible microtiming output */
 	if (pset.timing)
@@ -1299,7 +1326,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
 		results = PQexec(pset.db, "BEGIN");
 		OK = AcceptResult(results) &&
 			(PQresultStatus(results) == PGRES_COMMAND_OK);
-		PQclear(results);
+		ClearOrSaveResult(results);
 		if (!OK)
 			return false;
 		started_txn = true;
@@ -1313,7 +1340,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
 	results = PQexec(pset.db, buf.data);
 	OK = AcceptResult(results) &&
 		(PQresultStatus(results) == PGRES_COMMAND_OK);
-	PQclear(results);
+	ClearOrSaveResult(results);
 	termPQExpBuffer(&buf);
 	if (!OK)
 		goto cleanup;
@@ -1384,7 +1411,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
 
 			OK = AcceptResult(results);
 			Assert(!OK);
-			PQclear(results);
+			ClearOrSaveResult(results);
 			break;
 		}
 
@@ -1392,7 +1419,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
 		{
 			/* StoreQueryTuple will complain if not exactly one row */
 			OK = StoreQueryTuple(results);
-			PQclear(results);
+			ClearOrSaveResult(results);
 			break;
 		}
 
@@ -1415,7 +1442,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
 
 		printQuery(results, &my_popt, fout, is_pager, pset.logfile);
 
-		PQclear(results);
+		ClearOrSaveResult(results);
 
 		/* after the first result set, disallow header decoration */
 		my_popt.topt.start_table = false;
@@ -1473,14 +1500,14 @@ cleanup:
 		OK = AcceptResult(results) &&
 			(PQresultStatus(results) == PGRES_COMMAND_OK);
 	}
-	PQclear(results);
+	ClearOrSaveResult(results);
 
 	if (started_txn)
 	{
 		results = PQexec(pset.db, OK ? "COMMIT" : "ROLLBACK");
 		OK &= AcceptResult(results) &&
 			(PQresultStatus(results) == PGRES_COMMAND_OK);
-		PQclear(results);
+		ClearOrSaveResult(results);
 	}
 
 	if (pset.timing)
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 59f6f259dcda74f9090c6c0af46b916d6cfa506f..c6f0993018fa3e9c41a9eb15a788554b5f4dbb27 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -168,10 +168,11 @@ 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(109, pager ? &(pset.popt.topt) : NULL);
+	output = PageOutput(110, pager ? &(pset.popt.topt) : NULL);
 
 	fprintf(output, _("General\n"));
 	fprintf(output, _("  \\copyright             show PostgreSQL usage and distribution terms\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, _("  \\gset [PREFIX]         execute query and store results in psql variables\n"));
 	fprintf(output, _("  \\q                     quit psql\n"));
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 159a7a5579a942cdb7bebd20826dc3222a9a0e3b..ae30b2e60e3ba333f6994a9296eaf4b7fa1075ba 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -86,6 +86,8 @@ typedef struct _psqlSettings
 
 	FILE	   *copyStream;		/* Stream to read/write for \copy command */
 
+	PGresult   *last_error_result;		/* most recent error result, if any */
+
 	printQueryOpt popt;
 
 	char	   *gfname;			/* one-shot file output argument for \g */
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 07e94d064a39a8e5c2608cd07f739b8f532efd0d..b96cdc445e4c8b5d4ffac702f7a33ff4a2f144c7 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -135,6 +135,7 @@ main(int argc, char *argv[])
 	pset.queryFout = stdout;
 	pset.queryFoutPipe = false;
 	pset.copyStream = NULL;
+	pset.last_error_result = NULL;
 	pset.cur_cmd_source = stdin;
 	pset.cur_cmd_interactive = false;
 
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index eb592bb395fcbc3504b99a7d902e4d09bfd1d9b8..688d92a4520772c471a64b0596affb3fa6d33787 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1280,7 +1280,7 @@ psql_completion(const char *text, int start, int end)
 		"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
 		"\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\drds", "\\ds", "\\dS",
 		"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy",
-		"\\e", "\\echo", "\\ef", "\\encoding", "\\ev",
+		"\\e", "\\echo", "\\ef", "\\encoding", "\\errverbose", "\\ev",
 		"\\f", "\\g", "\\gset", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
 		"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
 		"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",