diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index c590f374c6..e201b5404e 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -5835,7 +5835,10 @@ merge_fdw_options(PgFdwRelationInfo *fpinfo,
 
 		/*
 		 * We'll prefer to consider this join async-capable if any table from
-		 * either side of the join is considered async-capable.
+		 * either side of the join is considered async-capable.  This would be
+		 * reasonable because in that case the foreign server would have its
+		 * own resources to scan that table asynchronously, and the join could
+		 * also be computed asynchronously using the resources.
 		 */
 		fpinfo->async_capable = fpinfo_o->async_capable ||
 			fpinfo_i->async_capable;
@@ -6893,6 +6896,9 @@ produce_tuple_asynchronously(AsyncRequest *areq, bool fetch)
 /*
  * Begin an asynchronous data fetch.
  *
+ * Note: this function assumes there is no currently-in-progress asynchronous
+ * data fetch.
+ *
  * Note: fetch_more_data must be called to fetch the result.
  */
 static void
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index c252757268..3c1f12adaf 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -952,7 +952,10 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result)
 
 	/* Nothing to do if there are no async subplans needing a new request. */
 	if (bms_is_empty(node->as_needrequest))
+	{
+		Assert(node->as_nasyncresults == 0);
 		return false;
+	}
 
 	/*
 	 * If there are any asynchronously-generated results that have not yet
@@ -998,17 +1001,16 @@ ExecAppendAsyncRequest(AppendState *node, TupleTableSlot **result)
 static void
 ExecAppendAsyncEventWait(AppendState *node)
 {
+	int			nevents = node->as_nasyncplans + 1;
 	long		timeout = node->as_syncdone ? -1 : 0;
 	WaitEvent   occurred_event[EVENT_BUFFER_SIZE];
 	int			noccurred;
-	int			nevents;
 	int			i;
 
 	/* We should never be called when there are no valid async subplans. */
 	Assert(node->as_nasyncremain > 0);
 
-	node->as_eventset = CreateWaitEventSet(CurrentMemoryContext,
-										   node->as_nasyncplans + 1);
+	node->as_eventset = CreateWaitEventSet(CurrentMemoryContext, nevents);
 	AddWaitEventToSet(node->as_eventset, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
 					  NULL, NULL);
 
@@ -1022,8 +1024,14 @@ ExecAppendAsyncEventWait(AppendState *node)
 			ExecAsyncConfigureWait(areq);
 	}
 
-	/* Wait for at least one event to occur. */
-	nevents = Min(node->as_nasyncplans + 1, EVENT_BUFFER_SIZE);
+	/* We wait on at most EVENT_BUFFER_SIZE events. */
+	if (nevents > EVENT_BUFFER_SIZE)
+		nevents = EVENT_BUFFER_SIZE;
+
+	/*
+	 * If the timeout is -1, wait until at least one event occurs.  If the
+	 * timeout is 0, poll for events, but do not wait at all.
+	 */
 	noccurred = WaitEventSetWait(node->as_eventset, timeout, occurred_event,
 								 nevents, WAIT_EVENT_APPEND_READY);
 	FreeWaitEventSet(node->as_eventset);
