diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index ab4c72762d..b5505a657b 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2182,6 +2182,8 @@ asyncQueueAdvanceTail(void)
 static void
 ProcessIncomingNotify(bool flush)
 {
+	MemoryContext oldcontext;
+
 	/* We *must* reset the flag */
 	notifyInterruptPending = false;
 
@@ -2196,14 +2198,23 @@ ProcessIncomingNotify(bool flush)
 
 	/*
 	 * We must run asyncQueueReadAllNotifications inside a transaction, else
-	 * bad things happen if it gets an error.
+	 * bad things happen if it gets an error.  However, we need to preserve
+	 * the caller's memory context: CommitTransactionCommand will set
+	 * CurrentMemoryContext to TopMemoryContext, risking long-lived memory
+	 * leaks if we leave it like that.
 	 */
+	oldcontext = CurrentMemoryContext;
+
 	StartTransactionCommand();
 
 	asyncQueueReadAllNotifications();
 
 	CommitTransactionCommand();
 
+	/* Caller's context had better not have been transaction-local */
+	Assert(MemoryContextIsValid(oldcontext));
+	MemoryContextSwitchTo(oldcontext);
+
 	/*
 	 * If this isn't an end-of-command case, we must flush the notify messages
 	 * to ensure frontend gets them promptly.
