diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 1393716587..5dead1926e 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -420,6 +420,15 @@ static bool postgresIsForeignPathAsyncCapable(ForeignPath *path);
 static void postgresForeignAsyncRequest(AsyncRequest *areq);
 static void postgresForeignAsyncConfigureWait(AsyncRequest *areq);
 static void postgresForeignAsyncNotify(AsyncRequest *areq);
+static Path *postgresPushDownLimit(PlannerInfo *root,
+								   RelOptInfo *rel,
+								   ForeignPath *fpath,
+								   Node *limitOffset,
+								   Node *limitCount,
+								   LimitOption limitOption,
+								   int64 offset_est,
+								   int64 count_est);
+
 
 /*
  * Helper functions
@@ -608,6 +617,8 @@ postgres_fdw_handler(PG_FUNCTION_ARGS)
 	routine->ForeignAsyncConfigureWait = postgresForeignAsyncConfigureWait;
 	routine->ForeignAsyncNotify = postgresForeignAsyncNotify;
 
+	routine->PushDownLimit = postgresPushDownLimit;
+
 	PG_RETURN_POINTER(routine);
 }
 
@@ -7822,3 +7833,26 @@ get_batch_size_option(Relation rel)
 
 	return batch_size;
 }
+
+static Path *postgresPushDownLimit(PlannerInfo *root,
+								   RelOptInfo *rel,
+								   ForeignPath *fpath,
+								   Node *limitOffset,
+								   Node *limitCount,
+								   LimitOption limitOption,
+								   int64 offset_est,
+								   int64 count_est)
+{
+	/*
+	 * TODO Implement this !!!
+	 */
+	return create_limit_path(
+		root,
+		rel,
+		fpath,
+		limitOffset,
+		limitCount,
+		limitOption,
+		offset_est,
+		count_est);
+}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 34ca6d4ac2..f977873624 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1194,6 +1194,20 @@ mark_async_capable_plan(Plan *plan, Path *path)
 										((ProjectionPath *) path)->subpath))
 				return true;
 			return false;
+		case T_LimitPath:
+			/*
+			 * If the generated plan node includes a Result node for the
+			 * projection, we can't execute it asynchronously.
+			 */
+			if (IsA(plan, Result))
+				return false;
+
+			/*
+			* Limit node is async capable iff its child is async capable
+			*/
+			LimitPath *lpath = (LimitPath *) path;
+			return mark_async_capable_plan(plan->lefttree, lpath->subpath);
+			
 		default:
 			return false;
 	}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index aafef24cf1..a4c5d85a17 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1773,11 +1773,11 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
 		 */
 		if (limit_needed(parse))
 		{
-			path = (Path *) create_limit_path(root, final_rel, path,
-											  parse->limitOffset,
-											  parse->limitCount,
-											  parse->limitOption,
-											  offset_est, count_est);
+			path = (Path *) pushdown_limit(root, final_rel, path,
+										   parse->limitOffset,
+										   parse->limitCount,
+										   parse->limitOption,
+										   offset_est, count_est);
 		}
 
 		/*
@@ -2410,7 +2410,7 @@ select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
  * for OFFSET but a little bit bogus for LIMIT: effectively we estimate
  * LIMIT 0 as though it were LIMIT 1.  But this is in line with the planner's
  * usual practice of never estimating less than one row.)  These values will
- * be passed to create_limit_path, which see if you change this code.
+ * be passed to pushdown_limit, which see if you change this code.
  *
  * The return value is the suitably adjusted tuple_fraction to use for
  * planning the query.  This adjustment is not overridable, since it reflects
@@ -5033,9 +5033,9 @@ create_final_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel,
 				 * not seem worth troubling over too much.
 				 */
 				add_path(distinct_rel, (Path *)
-						 create_limit_path(root, distinct_rel, sorted_path,
-										   NULL, limitCount,
-										   LIMIT_OPTION_COUNT, 0, 1));
+						 pushdown_limit(root, distinct_rel, sorted_path,
+										NULL, limitCount,
+										LIMIT_OPTION_COUNT, 0, 1));
 			}
 			else
 			{
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 211ba65389..c1624b791c 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -56,6 +56,21 @@ static int	append_startup_cost_compare(const ListCell *a, const ListCell *b);
 static List *reparameterize_pathlist_by_child(PlannerInfo *root,
 											  List *pathlist,
 											  RelOptInfo *child_rel);
+static Path *pushdown_limit_append(PlannerInfo *root, RelOptInfo *rel,
+								   AppendPath *appendPath,
+								   Node *limitOffset, Node *limitCount,
+								   LimitOption limitOption,
+								   int64 offset_est, int64 count_est);
+static Path *pushdown_limit_merge_append(PlannerInfo *root, RelOptInfo *rel,
+					 					 MergeAppendPath *mergeAppendPath,
+										 Node *limitOffset, Node *limitCount,
+										 LimitOption limitOption,
+										 int64 offset_est, int64 count_est);
+static Path * pushdown_limit_recurse(PlannerInfo *root, RelOptInfo *rel,
+									 Path *subpath,
+									 Node *limitOffset, Node *limitCount,
+									 LimitOption limitOption,
+									 int64 offset_est, int64 count_est);
 
 
 /*****************************************************************************
@@ -3742,6 +3757,206 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
 	return pathnode;
 }
 
+/*
+ * limit_path
+ *	Pushes down LIMIT.
+ *
+ * Potentially creates a LimitPath.
+ */
+Path *pushdown_limit(PlannerInfo *root, RelOptInfo *rel,
+					 Path *subpath,
+					 Node *limitOffset, Node *limitCount,
+					 LimitOption limitOption,
+					 int64 offset_est, int64 count_est)
+{
+	switch (subpath->pathtype)
+	{
+		case T_Append:
+			if (limitOffset == NULL)
+			{
+				return pushdown_limit_append(
+					root,
+					rel,
+					(AppendPath *) subpath,
+					limitOffset,
+					limitCount,
+					limitOption,
+					offset_est,
+					count_est);
+			}
+			break;
+		case T_MergeAppend:
+			if (limitOffset == NULL)
+			{
+				return pushdown_limit_merge_append(
+					root,
+					rel,
+					(MergeAppendPath *) subpath,
+					limitOffset,
+					limitCount,
+					limitOption,
+					offset_est,
+					count_est);
+			}
+			break;
+		default:
+			break;
+	}
+	/*
+	 * Wrap subpath in LimitPath node by default
+	 */
+	return (Path *) create_limit_path(
+		root,
+		rel,
+		subpath,
+		limitOffset,
+		limitCount,
+		limitOption,
+		offset_est,
+		count_est);
+}
+
+static
+Path *pushdown_limit_append(PlannerInfo *root, RelOptInfo *rel,
+					 		AppendPath *appendPath,
+							Node *limitOffset, Node *limitCount,
+							LimitOption limitOption,
+							int64 offset_est, int64 count_est)
+{
+	List       *children = NIL;
+	List       *partialChildren = NIL;
+	Relids required_outer = NULL;
+	ListCell   *l;
+	int        i;
+	i = 0;
+	foreach(l, appendPath->subpaths) {
+		Path   *child = (Path*) lfirst(l);
+		child = (Path *) pushdown_limit_recurse(
+			root,
+			child->parent,
+			child,
+			limitOffset,
+			limitCount,
+			limitOption,
+			offset_est,
+			count_est);
+		if (i < appendPath->first_partial_path) {
+			children = lappend(children, child);
+		}
+		else {
+			partialChildren = lappend(partialChildren, child);
+		}
+		i++;
+	}
+	if (appendPath->path.param_info != NULL) {
+		required_outer = appendPath->path.param_info->ppi_req_outer;
+	}
+	Path *subpath = (Path *) create_append_path(
+			root,
+			appendPath->path.parent,
+			children,
+			partialChildren,
+			appendPath->path.pathkeys,
+			required_outer,
+			appendPath->path.parallel_workers,
+			appendPath->path.parallel_aware,
+			i * count_est);
+	return (Path *) create_limit_path(
+		root,
+		rel,
+		subpath,
+		limitOffset,
+		limitCount,
+		limitOption,
+		offset_est,
+		count_est);
+}
+
+static
+Path *pushdown_limit_merge_append(PlannerInfo *root, RelOptInfo *rel,
+					 			  MergeAppendPath *mergeAppendPath,
+								  Node *limitOffset, Node *limitCount,
+								  LimitOption limitOption,
+								  int64 offset_est, int64 count_est)
+{
+	Relids    required_outer = NULL;
+	List     *children = NIL;
+	ListCell *l;
+	foreach(l, mergeAppendPath->subpaths) {
+		Path   *child = (Path*) lfirst(l);
+		child = (Path *) pushdown_limit_recurse(
+			root,
+			child->parent,
+			child,
+			limitOffset,
+			limitCount,
+			limitOption,
+			offset_est,
+			count_est);
+		children = lappend(children, child);
+	}
+	if (mergeAppendPath->path.param_info != NULL) {
+		required_outer = mergeAppendPath->path.param_info->ppi_req_outer;
+	}
+	Path *subpath = (Path *) create_merge_append_path(
+		root,
+		mergeAppendPath->path.parent,
+		children,
+		mergeAppendPath->path.pathkeys,
+		required_outer);
+	return (Path *) create_limit_path(
+		root,
+		rel,
+		subpath,
+		limitOffset,
+		limitCount,
+		limitOption,
+		offset_est,
+		count_est);
+}
+
+static
+Path *pushdown_limit_recurse(PlannerInfo *root, RelOptInfo *rel,
+							 Path *subpath,
+							 Node *limitOffset, Node *limitCount,
+							 LimitOption limitOption,
+							 int64 offset_est, int64 count_est)
+{
+	switch (subpath->pathtype)
+	{
+		case T_ForeignScan:
+			{
+				ForeignPath	*fpath = (ForeignPath*) subpath;
+				PushDownLimit_function pushDownLimit = rel->fdwroutine->PushDownLimit;
+				if (pushDownLimit)
+				{
+					return pushDownLimit(
+						root,
+						rel,
+						fpath,
+						limitOffset,
+						limitCount,
+						limitOption,
+						offset_est,
+						count_est);
+				}
+			}
+			break;
+		default:
+			break;
+	}
+
+	return (Path *) create_limit_path(
+		root,
+		rel,
+		subpath,
+		limitOffset,
+		limitCount,
+		limitOption,
+		offset_est,
+		count_est);
+}
+
 /*
  * create_limit_path
  *	  Creates a pathnode that represents performing LIMIT/OFFSET
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 996c62e305..1606d2c095 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -191,6 +191,15 @@ typedef void (*ForeignAsyncConfigureWait_function) (AsyncRequest *areq);
 
 typedef void (*ForeignAsyncNotify_function) (AsyncRequest *areq);
 
+typedef Path *(*PushDownLimit_function) (PlannerInfo *root,
+										 RelOptInfo *rel,
+										 ForeignPath *fpath,
+										 Node *limitOffset,
+										 Node *limitCount,
+										 LimitOption limitOption,
+										 int64 offset_est,
+										 int64 count_est);
+
 /*
  * FdwRoutine is the struct returned by a foreign-data wrapper's handler
  * function.  It provides pointers to the callback functions needed by the
@@ -278,6 +287,8 @@ typedef struct FdwRoutine
 	ForeignAsyncRequest_function ForeignAsyncRequest;
 	ForeignAsyncConfigureWait_function ForeignAsyncConfigureWait;
 	ForeignAsyncNotify_function ForeignAsyncNotify;
+
+	PushDownLimit_function PushDownLimit;
 } FdwRoutine;
 
 
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 6e557bebc4..8952fe39e7 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -284,11 +284,16 @@ extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
 												List *withCheckOptionLists, List *returningLists,
 												List *rowMarks, OnConflictExpr *onconflict,
 												List *mergeActionLists, int epqParam);
+extern Path *pushdown_limit(PlannerInfo *root, RelOptInfo *rel,
+							Path *subpath,
+							Node *limitOffset, Node *limitCount,
+							LimitOption limitOption,
+							int64 offset_est, int64 count_est);
 extern LimitPath *create_limit_path(PlannerInfo *root, RelOptInfo *rel,
-									Path *subpath,
-									Node *limitOffset, Node *limitCount,
-									LimitOption limitOption,
-									int64 offset_est, int64 count_est);
+							   		Path *subpath,
+							   		Node *limitOffset, Node *limitCount,
+							   		LimitOption limitOption,
+							   		int64 offset_est, int64 count_est);
 extern void adjust_limit_rows_costs(double *rows,
 									Cost *startup_cost, Cost *total_cost,
 									int64 offset_est, int64 count_est);
