diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 03e6d9ce8f..3a525839a7 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -1063,26 +1063,28 @@ PrintQueryResult(PGresult *result, bool last, bool is_watch, const printQueryOpt
 
 /*
  * Data structure and functions to record notices while they are
- * emitted, so that they can be shown later.
- *
- * We need to know which result is last, which requires to extract
- * one result in advance, hence two buffers are needed.
+ * emitted, so that they can be shown later. "print" tells whether
+ * to print or to store the messages.
  */
 struct t_notice_messages
 {
-	PQExpBufferData messages[2];
-	int			current;
+	PQExpBufferData	messages;
+	volatile bool	print;
 };
 
 /*
  * Store notices in appropriate buffer, for later display.
+ * This function is called by a signal handler.
  */
 static void
-AppendNoticeMessage(void *arg, const char *msg)
+AppendOrPrintNoticeMessage(void *arg, const char *msg)
 {
 	struct t_notice_messages *notices = arg;
 
-	appendPQExpBufferStr(&notices->messages[notices->current], msg);
+	if (notices->print)
+		pg_log_info("%s", msg);
+	else
+		appendPQExpBufferStr(&notices->messages, msg);
 }
 
 /*
@@ -1091,11 +1093,18 @@ AppendNoticeMessage(void *arg, const char *msg)
 static void
 ShowNoticeMessage(struct t_notice_messages *notices)
 {
-	PQExpBufferData *current = &notices->messages[notices->current];
+	bool print = notices->print;
+	PQExpBufferData *shown = &notices->messages;
 
-	if (*current->data != '\0')
-		pg_log_info("%s", current->data);
-	resetPQExpBuffer(current);
+	/* avoid race condition on the buffer which could lose messages */
+	notices->print = true;
+
+	if (*shown->data != '\0')
+		pg_log_info("%s", shown->data);
+	resetPQExpBuffer(shown);
+
+	/* restore previous printing status */
+	notices->print = print;
 }
 
 
@@ -1478,6 +1487,8 @@ static int
 ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_gone_p,
 						   bool is_watch, const printQueryOpt *opt, FILE *printQueryFout)
 {
+	/* whether we need to know whether a result is the last early */
+	bool		need_last = pset.gset_prefix || pset.gexec_flag || pset.crosstab_flag || !pset.show_all_results;
 	bool		timing = pset.timing;
 	bool		success;
 	instr_time	before,
@@ -1513,11 +1524,10 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 		return 0;
 	}
 
-	/* intercept notices */
-	notices.current = 0;
-	initPQExpBuffer(&notices.messages[0]);
-	initPQExpBuffer(&notices.messages[1]);
-	PQsetNoticeProcessor(pset.db, AppendNoticeMessage, &notices);
+	/* intercept notices, or not, depending on show mode */
+	notices.print = true;
+	initPQExpBuffer(&notices.messages);
+	PQsetNoticeProcessor(pset.db, AppendOrPrintNoticeMessage, &notices);
 
 	/* first result */
 	result = PQgetResult(pset.db);
@@ -1528,6 +1538,13 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 		PGresult   *next_result;
 		bool		last;
 
+		/*
+		 * Notices coming in from now on are attributed to the next (future) result,
+		 * so direct printing is suspended till this current result is displayed, but
+		 * only if it is really going to be displayed.
+		 */
+		notices.print = !pset.show_all_results;
+
 		if (!AcceptResult(result, false))
 		{
 			/*
@@ -1536,10 +1553,13 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 			 */
 			const char *error = PQresultErrorMessage(result);
 
-			ShowNoticeMessage(&notices);
 			if (strlen(error))
 				pg_log_info("%s", error);
 
+			/* then reactivate notice flow till next result */
+			notices.print = true;
+			ShowNoticeMessage(&notices);
+
 			CheckConnection();
 			if (!is_watch)
 				SetResultVariables(result, false);
@@ -1566,6 +1586,9 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 			else
 				result = PQgetResult(pset.db);
 
+			/* suspend notice flow again after the result, if needed */
+			notices.print = !pset.show_all_results;
+
 			/*
 			 * Get current timing measure in case an error occurs
 			 */
@@ -1601,8 +1624,6 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 		if (result_status == PGRES_COPY_IN ||
 			result_status == PGRES_COPY_OUT)
 		{
-			ShowNoticeMessage(&notices);
-
 			if (is_watch)
 			{
 				ClearOrSaveAllResults();
@@ -1610,22 +1631,38 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 				return -1;
 			}
 
-			/* use normal notice processor during COPY */
-			PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
+			/* back to normal notice processor during COPY */
+			notices.print = true;
+			ShowNoticeMessage(&notices);
 
 			success &= HandleCopyResult(&result);
 
-			PQsetNoticeProcessor(pset.db, AppendNoticeMessage, &notices);
+			notices.print = !pset.show_all_results;
 		}
 
 		/*
 		 * Check PQgetResult() again.  In the typical case of a single-command
 		 * string, it will return NULL.  Otherwise, we'll have other results
 		 * to process.  We need to do that to check whether this is the last.
+		 *
+		 * Note that notices are possibly suspended while waiting for the next
+		 * result because the previous result has not been displayed yet.
+		 *
+		 * If the next queries takes some time, the output of the current query
+		 * is suspended, eg "SELECT 0 \; SELECT take_long_time() \gset" will wait
+		 * before showing the initial 0. The notices are shown anyway, possibly out
+		 * of order, as a tradeoff between keeping the order vs delaying the notices.
 		 */
-		notices.current ^= 1;
-		next_result = PQgetResult(pset.db);
-		notices.current ^= 1;
+		if (need_last)
+		{
+			notices.print = true;
+			ShowNoticeMessage(&notices);
+			next_result = PQgetResult(pset.db);
+			notices.print = !pset.show_all_results;
+		}
+		else
+			next_result = NULL;
+
 		last = (next_result == NULL);
 
 		/*
@@ -1647,19 +1684,28 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 			*elapsed_msec = INSTR_TIME_GET_MILLISEC(after);
 		}
 
-		/* notices already shown above for copy */
-		ShowNoticeMessage(&notices);
-
 		/* this may or may not print something depending on settings */
 		if (result != NULL)
+		{
 			success &= PrintQueryResult(result, last, false, opt, printQueryFout);
 
+			/* reactivate notice flow after printing the result */
+			notices.print = true;
+			ShowNoticeMessage(&notices);
+		}
+
+		/* we need to know whether it was the last now anyway */
+		if (!need_last)
+		{
+			next_result = PQgetResult(pset.db);
+			last = (next_result == NULL);
+		}
+
 		/* set variables on last result if all went well */
 		if (!is_watch && last && success)
 			SetResultVariables(result, true);
 
 		ClearOrSaveResult(result);
-		notices.current ^= 1;
 		result = next_result;
 
 		if (cancel_pressed)
@@ -1669,10 +1715,13 @@ ExecQueryAndProcessResults(const char *query, double *elapsed_msec, bool *svpt_g
 		}
 	}
 
-	/* reset notice hook */
+	/* reset standard notice hook */
 	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
-	termPQExpBuffer(&notices.messages[0]);
-	termPQExpBuffer(&notices.messages[1]);
+
+	/* flush notices if any, before cleaning up */
+	notices.print = true;
+	ShowNoticeMessage(&notices);
+	termPQExpBuffer(&notices.messages);
 
 	/* may need this to recover from conn loss during COPY */
 	if (!CheckConnection())
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 2a38a93a3b..baedf04ba5 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -5335,13 +5335,13 @@ CONTEXT:  PL/pgSQL function warn(text) line 2 at RAISE
 
 -- \gset applies to last query only
 SELECT 3 AS three \; SELECT warn('3.5') \; SELECT 4 AS four \gset
+NOTICE:  warn 3.5
+CONTEXT:  PL/pgSQL function warn(text) line 2 at RAISE
  three 
 -------
      3
 (1 row)
 
-NOTICE:  warn 3.5
-CONTEXT:  PL/pgSQL function warn(text) line 2 at RAISE
  warn 
 ------
  t
