diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index b93b4fc..0a3e6d6 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -569,7 +569,7 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
 
 				if (proparallel != PROPARALLEL_SAFE)
 					return;
-				if (!is_parallel_safe(root, (Node *) rte->tablesample->args))
+				if (!is_parallel_safe(root, (Node *) rte->tablesample->args, NIL))
 					return;
 			}
 
@@ -622,7 +622,7 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
 
 		case RTE_FUNCTION:
 			/* Check for parallel-restricted functions. */
-			if (!is_parallel_safe(root, (Node *) rte->functions))
+			if (!is_parallel_safe(root, (Node *) rte->functions, NIL))
 				return;
 			break;
 
@@ -632,7 +632,7 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
 
 		case RTE_VALUES:
 			/* Check for parallel-restricted functions. */
-			if (!is_parallel_safe(root, (Node *) rte->values_lists))
+			if (!is_parallel_safe(root, (Node *) rte->values_lists, NIL))
 				return;
 			break;
 
@@ -664,14 +664,14 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
 	 * outer join clauses work correctly.  It would likely break equivalence
 	 * classes, too.
 	 */
-	if (!is_parallel_safe(root, (Node *) rel->baserestrictinfo))
+	if (!is_parallel_safe(root, (Node *) rel->baserestrictinfo, NIL))
 		return;
 
 	/*
 	 * Likewise, if the relation's outputs are not parallel-safe, give up.
 	 * (Usually, they're just Vars, but sometimes they're not.)
 	 */
-	if (!is_parallel_safe(root, (Node *) rel->reltarget->exprs))
+	if (!is_parallel_safe(root, (Node *) rel->reltarget->exprs, NIL))
 		return;
 
 	/* We have a winner. */
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index ef0de3f..a8d10e0 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -77,7 +77,7 @@ query_planner(PlannerInfo *root, List *tlist,
 		 */
 		if (root->glob->parallelModeOK)
 			final_rel->consider_parallel =
-				is_parallel_safe(root, parse->jointree->quals);
+				is_parallel_safe(root, parse->jointree->quals, NIL);
 
 		/* The only path for it is a trivial Result path */
 		add_path(final_rel, (Path *)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 649a233..9c31aa3 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1809,7 +1809,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 		 * computed by partial paths.
 		 */
 		if (current_rel->partial_pathlist &&
-			is_parallel_safe(root, (Node *) scanjoin_target->exprs))
+			is_parallel_safe(root, (Node *) scanjoin_target->exprs, NIL))
 		{
 			/* Apply the scan/join target to each partial path */
 			foreach(lc, current_rel->partial_pathlist)
@@ -1944,8 +1944,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 	 * query.
 	 */
 	if (current_rel->consider_parallel &&
-		is_parallel_safe(root, parse->limitOffset) &&
-		is_parallel_safe(root, parse->limitCount))
+		is_parallel_safe(root, parse->limitOffset, NIL) &&
+		is_parallel_safe(root, parse->limitCount, NIL))
 		final_rel->consider_parallel = true;
 
 	/*
@@ -3530,8 +3530,8 @@ create_grouping_paths(PlannerInfo *root,
 	 * target list and HAVING quals are parallel-safe.
 	 */
 	if (input_rel->consider_parallel &&
-		is_parallel_safe(root, (Node *) target->exprs) &&
-		is_parallel_safe(root, (Node *) parse->havingQual))
+		is_parallel_safe(root, (Node *) target->exprs, NIL) &&
+		is_parallel_safe(root, (Node *) parse->havingQual, NIL))
 		grouped_rel->consider_parallel = true;
 
 	/*
@@ -4502,8 +4502,8 @@ create_window_paths(PlannerInfo *root,
 	 * target list and active windows for non-parallel-safe constructs.
 	 */
 	if (input_rel->consider_parallel &&
-		is_parallel_safe(root, (Node *) output_target->exprs) &&
-		is_parallel_safe(root, (Node *) activeWindows))
+		is_parallel_safe(root, (Node *) output_target->exprs, NIL) &&
+		is_parallel_safe(root, (Node *) activeWindows, NIL))
 		window_rel->consider_parallel = true;
 
 	/*
@@ -4892,7 +4892,7 @@ create_ordered_paths(PlannerInfo *root,
 	 * target list is parallel-safe.
 	 */
 	if (input_rel->consider_parallel &&
-		is_parallel_safe(root, (Node *) target->exprs))
+		is_parallel_safe(root, (Node *) target->exprs, NIL))
 		ordered_rel->consider_parallel = true;
 
 	/*
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index c1be34d..959a660 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -57,7 +57,7 @@ typedef struct finalize_primnode_context
 static Node *build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
 			  List *plan_params,
 			  SubLinkType subLinkType, int subLinkId,
-			  Node *testexpr, bool adjust_testexpr,
+			  Node *testexpr, List *paramIds, bool adjust_testexpr,
 			  bool unknownEqFalse);
 static List *generate_subquery_params(PlannerInfo *root, List *tlist,
 						 List **paramIds);
@@ -550,7 +550,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
 	/* And convert to SubPlan or InitPlan format. */
 	result = build_subplan(root, plan, subroot, plan_params,
 						   subLinkType, subLinkId,
-						   testexpr, true, isTopQual);
+						   testexpr, NIL, true, isTopQual);
 
 	/*
 	 * If it's a correlated EXISTS with an unimportant targetlist, we might be
@@ -604,12 +604,11 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
 												  plan_params,
 												  ANY_SUBLINK, 0,
 												  newtestexpr,
+												  paramIds,
 												  false, true));
 				/* Check we got what we expected */
 				Assert(hashplan->parParam == NIL);
 				Assert(hashplan->useHashTable);
-				/* build_subplan won't have filled in paramIds */
-				hashplan->paramIds = paramIds;
 
 				/* Leave it to the executor to decide which plan to use */
 				asplan = makeNode(AlternativeSubPlan);
@@ -632,7 +631,7 @@ static Node *
 build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
 			  List *plan_params,
 			  SubLinkType subLinkType, int subLinkId,
-			  Node *testexpr, bool adjust_testexpr,
+			  Node *testexpr, List *paramIds, bool adjust_testexpr,
 			  bool unknownEqFalse)
 {
 	Node	   *result;
@@ -647,12 +646,12 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
 	splan = makeNode(SubPlan);
 	splan->subLinkType = subLinkType;
 	splan->testexpr = NULL;
-	splan->paramIds = NIL;
+	splan->paramIds = paramIds;
 	get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
 					   &splan->firstColCollation);
 	splan->useHashTable = false;
 	splan->unknownEqFalse = unknownEqFalse;
-	splan->parallel_safe = plan->parallel_safe;
+	splan->parallel_safe = false;
 	splan->setParam = NIL;
 	splan->parParam = NIL;
 	splan->args = NIL;
@@ -815,6 +814,13 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot,
 			splan->testexpr = testexpr;
 
 		/*
+		 * mark the subplan as parallel safe, iff the child plan and the
+		 * contained testexpr are parallel safe.
+		 */
+		splan->parallel_safe = plan->parallel_safe &&
+					is_parallel_safe(root, splan->testexpr, splan->paramIds);
+
+		/*
 		 * We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types to
 		 * initPlans, even when they are uncorrelated or undirect correlated,
 		 * because we need to scan the output of the subplan for each outer
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index e196c5e..8584e04 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -93,6 +93,7 @@ typedef struct
 {
 	char		max_hazard;		/* worst proparallel hazard found so far */
 	char		max_interesting;	/* worst proparallel hazard of interest */
+	List	   *safe_param_ids;	/* list of safe param ids */
 } max_parallel_hazard_context;
 
 static bool contain_agg_clause_walker(Node *node, void *context);
@@ -1056,6 +1057,7 @@ max_parallel_hazard(Query *parse)
 
 	context.max_hazard = PROPARALLEL_SAFE;
 	context.max_interesting = PROPARALLEL_UNSAFE;
+	context.safe_param_ids = NIL;
 	(void) max_parallel_hazard_walker((Node *) parse, &context);
 	return context.max_hazard;
 }
@@ -1064,11 +1066,15 @@ max_parallel_hazard(Query *parse)
  * is_parallel_safe
  *		Detect whether the given expr contains only parallel-safe functions
  *
+ * Any reference to safeParamIds in an expression is considered parallel-safe.
+ * Note that we must consider only those params as safe params which can be
+ * available in parallel part of the plan.
+ *
  * root->glob->maxParallelHazard must previously have been set to the
  * result of max_parallel_hazard() on the whole query.
  */
 bool
-is_parallel_safe(PlannerInfo *root, Node *node)
+is_parallel_safe(PlannerInfo *root, Node *node, List *safeParamIds)
 {
 	max_parallel_hazard_context context;
 
@@ -1084,6 +1090,7 @@ is_parallel_safe(PlannerInfo *root, Node *node)
 	/* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */
 	context.max_hazard = PROPARALLEL_SAFE;
 	context.max_interesting = PROPARALLEL_RESTRICTED;
+	context.safe_param_ids = safeParamIds;
 	return !max_parallel_hazard_walker(node, &context);
 }
 
@@ -1176,11 +1183,19 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 		return !((SubPlan *) node)->parallel_safe;
 
 	/*
-	 * We can't pass Params to workers at the moment either, so they are also
-	 * parallel-restricted.
+	 * We can't pass Params to workers at the moment, so except for reference
+	 * to safe_param_ids, they are considered parallel-restricted.
 	 */
 	else if (IsA(node, Param))
 	{
+		ListCell	*lc;
+
+		foreach(lc, context->safe_param_ids)
+		{
+			if (lfirst_int(lc) == ((Param *) node)->paramid)
+				return false;
+		}
+
 		if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
 			return true;
 	}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 2d5caae..e198d68 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -2292,7 +2292,7 @@ create_projection_path(PlannerInfo *root,
 	pathnode->path.parallel_aware = false;
 	pathnode->path.parallel_safe = rel->consider_parallel &&
 		subpath->parallel_safe &&
-		is_parallel_safe(root, (Node *) target->exprs);
+		is_parallel_safe(root, (Node *) target->exprs, NIL);
 	pathnode->path.parallel_workers = subpath->parallel_workers;
 	/* Projection does not change the sort order */
 	pathnode->path.pathkeys = subpath->pathkeys;
@@ -2399,7 +2399,7 @@ apply_projection_to_path(PlannerInfo *root,
 	 * target expressions, then we can't.
 	 */
 	if (IsA(path, GatherPath) &&
-		is_parallel_safe(root, (Node *) target->exprs))
+		is_parallel_safe(root, (Node *) target->exprs, NIL))
 	{
 		GatherPath *gpath = (GatherPath *) path;
 
@@ -2420,7 +2420,7 @@ apply_projection_to_path(PlannerInfo *root,
 								   target);
 	}
 	else if (path->parallel_safe &&
-			 !is_parallel_safe(root, (Node *) target->exprs))
+			 !is_parallel_safe(root, (Node *) target->exprs, NIL))
 	{
 		/*
 		 * We're inserting a parallel-restricted target list into a path
@@ -2460,7 +2460,7 @@ create_set_projection_path(PlannerInfo *root,
 	pathnode->path.parallel_aware = false;
 	pathnode->path.parallel_safe = rel->consider_parallel &&
 		subpath->parallel_safe &&
-		is_parallel_safe(root, (Node *) target->exprs);
+		is_parallel_safe(root, (Node *) target->exprs, NIL);
 	pathnode->path.parallel_workers = subpath->parallel_workers;
 	/* Projection does not change the sort order XXX? */
 	pathnode->path.pathkeys = subpath->pathkeys;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 342d884..1980cf5 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -593,8 +593,8 @@ build_join_rel(PlannerInfo *root,
 	 * here.
 	 */
 	if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
-		is_parallel_safe(root, (Node *) restrictlist) &&
-		is_parallel_safe(root, (Node *) joinrel->reltarget->exprs))
+		is_parallel_safe(root, (Node *) restrictlist, NIL) &&
+		is_parallel_safe(root, (Node *) joinrel->reltarget->exprs, NIL))
 		joinrel->consider_parallel = true;
 
 	/* Add the joinrel to the PlannerInfo. */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index cc0d7b0..17533f3 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -61,7 +61,8 @@ extern bool contain_mutable_functions(Node *clause);
 extern bool contain_volatile_functions(Node *clause);
 extern bool contain_volatile_functions_not_nextval(Node *clause);
 extern char max_parallel_hazard(Query *parse);
-extern bool is_parallel_safe(PlannerInfo *root, Node *node);
+extern bool is_parallel_safe(PlannerInfo *root, Node *node,
+					List *safeParamIds);
 extern bool contain_nonstrict_functions(Node *clause);
 extern bool contain_leaked_vars(Node *clause);
 
