diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 7a7177c550..5cb573f06f 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -5171,8 +5171,9 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
       </term>
       <listitem>
        <para>
-        Sets the query cost above which JIT compilation is activated, if
-        enabled (see <xref linkend="jit"/>).
+        Sets the cost threshold for which a given plan node will consider
+        performing JIT compilation for itself.  xref linkend="jit"/> must also
+        be enabled.
         Performing <acronym>JIT</acronym> costs planning time but can
         accelerate query execution.
         Setting this to <literal>-1</literal> disables JIT compilation.
@@ -5189,10 +5190,11 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
       </term>
       <listitem>
        <para>
-        Sets the query cost above which JIT compilation attempts to inline
-        functions and operators.  Inlining adds planning time, but can
-        improve execution speed.  It is not meaningful to set this to less
-        than <varname>jit_above_cost</varname>.
+        Sets the cost threshold for which a given plan node will consider
+        inlining functions and operators using JIT compilation.  Inlining adds
+        additional overhead during executor start-up, but can improve
+        performance during execution.  It is not meaningful to set this to
+        less than <varname>jit_above_cost</varname>.
         Setting this to <literal>-1</literal> disables inlining.
         The default is <literal>500000</literal>.
        </para>
@@ -5207,13 +5209,14 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
       </term>
       <listitem>
        <para>
-        Sets the query cost above which JIT compilation applies expensive
-        optimizations.  Such optimization adds planning time, but can improve
-        execution speed.  It is not meaningful to set this to less
-        than <varname>jit_above_cost</varname>, and it is unlikely to be
-        beneficial to set it to more
-        than <varname>jit_inline_above_cost</varname>.
-        Setting this to <literal>-1</literal> disables expensive optimizations.
+        Sets the cost threshold for which a given plan node will consider
+        performing an optimization pass during JIT compilation for itself.
+        This compilation adds further overhead during executor start-up, but
+        can provide an additional boost to performance during execution.  It
+        is not meaningful to set this to less than
+        <varname>jit_above_cost</varname>, and it is unlikely to be beneficial
+        to set it to more than <varname>jit_inline_above_cost</varname>. 
+        Setting this to <literal>-1</literal> disables the optimization pass.
         The default is <literal>500000</literal>.
        </para>
       </listitem>
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 88661217e9..a8ec488488 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -296,22 +296,8 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
 		if (estate->es_subplanstates &&
 			contain_subplans((Node *) exprs))
 		{
-			int			saved_jit_flags;
-
-			/*
-			 * As these expressions are only used once, disable JIT for them.
-			 * This is worthwhile because it's common to insert significant
-			 * amounts of data via VALUES().  Note that this doesn't prevent
-			 * use of JIT *within* a subplan, since that's initialized
-			 * separately; this just affects the upper-level subexpressions.
-			 */
-			saved_jit_flags = estate->es_jit_flags;
-			estate->es_jit_flags = PGJIT_NONE;
-
 			scanstate->exprstatelists[i] = ExecInitExprList(exprs,
 															&scanstate->ss.ps);
-
-			estate->es_jit_flags = saved_jit_flags;
 		}
 		i++;
 	}
diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c
index 5ca3f922fe..362a9f7a11 100644
--- a/src/backend/jit/jit.c
+++ b/src/backend/jit/jit.c
@@ -165,11 +165,11 @@ jit_compile_expr(struct ExprState *state)
 		return false;
 
 	/* if no jitting should be performed at all */
-	if (!(state->parent->state->es_jit_flags & PGJIT_PERFORM))
+	if (!(state->parent->plan->jitFlags & PGJIT_PERFORM))
 		return false;
 
 	/* or if expressions aren't JITed */
-	if (!(state->parent->state->es_jit_flags & PGJIT_EXPR))
+	if (!(state->parent->plan->jitFlags & PGJIT_EXPR))
 		return false;
 
 	/* this also takes !jit_enabled into account */
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index cca5c117a0..65586da719 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -137,7 +137,7 @@ llvm_compile_expr(ExprState *state)
 		context = (LLVMJitContext *) parent->state->es_jit;
 	else
 	{
-		context = llvm_create_context(parent->state->es_jit_flags);
+		context = llvm_create_context(state->parent->plan->jitFlags);
 		parent->state->es_jit = &context->base;
 	}
 
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 89c409de66..884ed9a60e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -121,6 +121,7 @@ CopyPlanFields(const Plan *from, Plan *newnode)
 	COPY_SCALAR_FIELD(plan_width);
 	COPY_SCALAR_FIELD(parallel_aware);
 	COPY_SCALAR_FIELD(parallel_safe);
+	COPY_SCALAR_FIELD(jitFlags);
 	COPY_SCALAR_FIELD(plan_node_id);
 	COPY_NODE_FIELD(targetlist);
 	COPY_NODE_FIELD(qual);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index e2f177515d..c3e4cccb17 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -334,6 +334,7 @@ _outPlanInfo(StringInfo str, const Plan *node)
 	WRITE_INT_FIELD(plan_width);
 	WRITE_BOOL_FIELD(parallel_aware);
 	WRITE_BOOL_FIELD(parallel_safe);
+	WRITE_INT_FIELD(jitFlags);
 	WRITE_INT_FIELD(plan_node_id);
 	WRITE_NODE_FIELD(targetlist);
 	WRITE_NODE_FIELD(qual);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 42050ab719..dabedd4017 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1572,6 +1572,7 @@ ReadCommonPlan(Plan *local_node)
 	READ_INT_FIELD(plan_width);
 	READ_BOOL_FIELD(parallel_aware);
 	READ_BOOL_FIELD(parallel_safe);
+	READ_INT_FIELD(jitFlags);
 	READ_INT_FIELD(plan_node_id);
 	READ_NODE_FIELD(targetlist);
 	READ_NODE_FIELD(qual);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 99278eed93..1e7933f0d6 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -22,6 +22,7 @@
 #include "access/sysattr.h"
 #include "catalog/pg_class.h"
 #include "foreign/fdwapi.h"
+#include "jit/jit.h"
 #include "miscadmin.h"
 #include "nodes/extensible.h"
 #include "nodes/makefuncs.h"
@@ -75,6 +76,7 @@ static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path,
 								 int flags);
 static Plan *create_scan_plan(PlannerInfo *root, Path *best_path,
 							  int flags);
+static void plan_consider_jit(PlannerInfo *root, Plan *plan);
 static List *build_path_tlist(PlannerInfo *root, Path *path);
 static bool use_physical_tlist(PlannerInfo *root, Path *path, int flags);
 static List *get_gating_quals(PlannerInfo *root, List *quals);
@@ -526,9 +528,53 @@ create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
 			break;
 	}
 
+	/* See about switching on JIT for this node */
+	plan_consider_jit(root, plan);
+
 	return plan;
 }
 
+static void
+plan_consider_jit(PlannerInfo *root, Plan *plan)
+{
+	plan->jitFlags = PGJIT_NONE;
+
+	/*
+	 * For values scans, expressions are only used once, so ensure we don't
+	 * enable JIT for them.
+	 */
+	if (IsA(plan, ValuesScan))
+		return;
+
+	 /* Determine which JIT options to enable for this plan node */
+	if (jit_enabled && jit_above_cost >= 0 &&
+		plan->total_cost > jit_above_cost)
+	{
+		plan->jitFlags |= PGJIT_PERFORM;
+
+		/*
+		 * Decide how much effort should be put into generating better code.
+		 */
+		if (jit_optimize_above_cost >= 0 &&
+			plan->total_cost > jit_optimize_above_cost)
+			plan->jitFlags |= PGJIT_OPT3;
+		if (jit_inline_above_cost >= 0 &&
+			plan->total_cost > jit_inline_above_cost)
+			plan->jitFlags |= PGJIT_INLINE;
+
+		/*
+		 * Decide which operations should be JITed.
+		 */
+		if (jit_expressions)
+			plan->jitFlags |= PGJIT_EXPR;
+		if (jit_tuple_deforming)
+			plan->jitFlags |= PGJIT_DEFORM;
+
+		/* Record the maximum flags used by any plan node */
+		root->glob->jitFlags |= plan->jitFlags;
+	}
+}
+
 /*
  * create_scan_plan
  *	 Create a scan plan for the parent relation of 'best_path'.
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index b40a112c25..ef9806887d 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -353,6 +353,8 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 		glob->parallelModeOK = false;
 	}
 
+	glob->jitFlags = PGJIT_NONE;
+
 	/*
 	 * glob->parallelModeNeeded is normally set to false here and changed to
 	 * true during plan creation if a Gather or Gather Merge plan is actually
@@ -532,32 +534,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 	result->utilityStmt = parse->utilityStmt;
 	result->stmt_location = parse->stmt_location;
 	result->stmt_len = parse->stmt_len;
-
-	result->jitFlags = PGJIT_NONE;
-	if (jit_enabled && jit_above_cost >= 0 &&
-		top_plan->total_cost > jit_above_cost)
-	{
-		result->jitFlags |= PGJIT_PERFORM;
-
-		/*
-		 * Decide how much effort should be put into generating better code.
-		 */
-		if (jit_optimize_above_cost >= 0 &&
-			top_plan->total_cost > jit_optimize_above_cost)
-			result->jitFlags |= PGJIT_OPT3;
-		if (jit_inline_above_cost >= 0 &&
-			top_plan->total_cost > jit_inline_above_cost)
-			result->jitFlags |= PGJIT_INLINE;
-
-		/*
-		 * Decide which operations should be JITed.
-		 */
-		if (jit_expressions)
-			result->jitFlags |= PGJIT_EXPR;
-		if (jit_tuple_deforming)
-			result->jitFlags |= PGJIT_DEFORM;
-	}
-
+	result->jitFlags = glob->jitFlags;
 	if (glob->partition_directory != NULL)
 		DestroyPartitionDirectory(glob->partition_directory);
 
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index cf832d7f90..02b8a57c92 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -589,9 +589,9 @@ typedef struct EState
 	struct dsa_area *es_query_dsa;
 
 	/*
-	 * JIT information. es_jit_flags indicates whether JIT should be performed
-	 * and with which options.  es_jit is created on-demand when JITing is
-	 * performed.
+	 * JIT information. es_jit_flags indicates the possible set of JIT options
+	 * that each plan node may make use of.  es_jit is created on-demand when
+	 * JITing is performed.
 	 *
 	 * es_jit_worker_instr is the combined, on demand allocated,
 	 * instrumentation from all workers. The leader's instrumentation is kept
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..dcfc401fb0 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -146,6 +146,8 @@ typedef struct PlannerGlobal
 
 	char		maxParallelHazard;	/* worst PROPARALLEL hazard level */
 
+	int			jitFlags;		/* OR mask of jitFlags for each plan node */
+
 	PartitionDirectory partition_directory; /* partition descriptors */
 } PlannerGlobal;
 
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 83e01074ed..aa7547bf6c 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -59,7 +59,8 @@ typedef struct PlannedStmt
 
 	bool		parallelModeNeeded; /* parallel mode required to execute? */
 
-	int			jitFlags;		/* which forms of JIT should be performed */
+	int			jitFlags;		/* OR mask of JIT flags which plan nodes may
+								 * use */
 
 	struct Plan *planTree;		/* tree of Plan nodes */
 
@@ -135,7 +136,10 @@ typedef struct Plan
 	bool		parallel_aware; /* engage parallel-aware logic? */
 	bool		parallel_safe;	/* OK to use as part of parallel plan? */
 
-	/*
+	int			jitFlags;		/* which forms of JIT should be performed on
+								 * this node */
+
+								 /*
 	 * Common structural data for all Plan types.
 	 */
 	int			plan_node_id;	/* unique across entire final plan tree */
