diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index d79e4cc..9de1129 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -283,6 +283,8 @@ static void postgresGetForeignJoinPaths(PlannerInfo *root,
 							JoinPathExtraData *extra);
 static bool postgresRecheckForeignScan(ForeignScanState *node,
 						   TupleTableSlot *slot);
+static bool postgresIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
+											  RangeTblEntry *rte);
 static List *get_useful_pathkeys_for_relation(PlannerInfo *root,
 								 RelOptInfo *rel);
 static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
@@ -350,6 +352,7 @@ postgres_fdw_handler(PG_FUNCTION_ARGS)
 	routine->IterateForeignScan = postgresIterateForeignScan;
 	routine->ReScanForeignScan = postgresReScanForeignScan;
 	routine->EndForeignScan = postgresEndForeignScan;
+	routine->IsForeignScanParallelSafe = postgresIsForeignScanParallelSafe;
 
 	/* Functions for updating foreign tables */
 	routine->AddForeignUpdateTargets = postgresAddForeignUpdateTargets;
@@ -2055,6 +2058,22 @@ postgresExplainForeignModify(ModifyTableState *mtstate,
 	}
 }
 
+/*
+ * postgresIsForeignScanParallelSafe
+ * 		Check if parallel scans are safe.
+ *
+ * In theory we could answer yes if we could somehow arrange to use an
+ * exported snapshot shared by backends, and we somehow knew that there could
+ * be no uncommitted changes in the lead process's transaction.  Only then
+ * could we be sure that a worker with its own FDW connection has the same
+ * view of the remote database as the leader.
+ */
+static bool
+postgresIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
+								  RangeTblEntry *rte)
+{
+	return false;
+}
 
 /*
  * estimate_path_cost_size
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index bcb668f..99b315c 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -527,6 +527,21 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
 					return;
 				return;
 			}
+
+			/*
+			 * Ask FDWs if they support pushing down scans.  Parallel workers
+			 * create separate FDW connections which may not be appropriately
+			 * coordinated between workers and the leader, so we default to
+			 * assuming no unless the FDW explicitly tells us otherwise.
+			 */
+			if (rte->relkind == RELKIND_FOREIGN_TABLE)
+			{
+				Assert(rel->fdwroutine);
+				if (!rel->fdwroutine->IsForeignScanParallelSafe)
+					return;
+				if (!rel->fdwroutine->IsForeignScanParallelSafe(root, rel, rte))
+					return;
+			}
 			break;
 
 		case RTE_SUBQUERY:
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 9fafab0..0c8251e 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -131,6 +131,10 @@ typedef void (*InitializeDSMForeignScan_function) (ForeignScanState *node,
 typedef void (*InitializeWorkerForeignScan_function) (ForeignScanState *node,
 													  shm_toc *toc,
 													  void *coordinate);
+typedef bool (*IsForeignScanParallelSafe_function) (PlannerInfo *root,
+													RelOptInfo *rel,
+													RangeTblEntry *rte);
+
 /*
  * FdwRoutine is the struct returned by a foreign-data wrapper's handler
  * function.  It provides pointers to the callback functions needed by the
@@ -188,6 +192,7 @@ typedef struct FdwRoutine
 	ImportForeignSchema_function ImportForeignSchema;
 
 	/* Support functions for parallelism under Gather node */
+	IsForeignScanParallelSafe_function IsForeignScanParallelSafe;
 	EstimateDSMForeignScan_function EstimateDSMForeignScan;
 	InitializeDSMForeignScan_function InitializeDSMForeignScan;
 	InitializeWorkerForeignScan_function InitializeWorkerForeignScan;
