{
    char        max_hazard;     /* worst proparallel hazard found so far */
    char        max_interesting;    /* worst proparallel hazard of interest */
+   List       *safe_param_ids; /* PARAM_EXEC Param IDs to treat as safe */
 } max_parallel_hazard_context;
 
 static bool contain_agg_clause_walker(Node *node, void *context);
 
    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;
 }
    /* 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 = NIL;
    return !max_parallel_hazard_walker(node, &context);
 }
 
            return true;
    }
 
-   /* We can push the subplans only if they are parallel-safe. */
+   /*
+    * Only parallel-safe SubPlans can be sent to workers.  Within the
+    * testexpr of the SubPlan, Params representing the output columns of the
+    * subplan can be treated as parallel-safe, so temporarily add their IDs
+    * to the safe_param_ids list while examining the testexpr.
+    */
    else if (IsA(node, SubPlan))
-       return !((SubPlan *) node)->parallel_safe;
+   {
+       SubPlan    *subplan = (SubPlan *) node;
+       List       *save_safe_param_ids;
+
+       if (!subplan->parallel_safe &&
+           max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
+           return true;
+       save_safe_param_ids = context->safe_param_ids;
+       context->safe_param_ids = list_concat(list_copy(subplan->paramIds),
+                                             context->safe_param_ids);
+       if (max_parallel_hazard_walker(subplan->testexpr, context))
+           return true;        /* no need to restore safe_param_ids */
+       context->safe_param_ids = save_safe_param_ids;
+       /* we must also check args, but no special Param treatment there */
+       if (max_parallel_hazard_walker((Node *) subplan->args, context))
+           return true;
+       /* don't want to recurse normally, so we're done */
+       return false;
+   }
 
    /*
     * We can't pass Params to workers at the moment either, so they are also
-    * parallel-restricted.
+    * parallel-restricted, unless they are PARAM_EXEC Params listed in
+    * safe_param_ids, meaning they could be generated within the worker.
     */
    else if (IsA(node, Param))
    {
-       if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
-           return true;
+       Param      *param = (Param *) node;
+
+       if (param->paramkind != PARAM_EXEC ||
+           !list_member_int(context->safe_param_ids, param->paramid))
+       {
+           if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
+               return true;
+       }
+       return false;           /* nothing to recurse to */
    }
 
    /*