diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index d2a2479822..27109311f7 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -24,6 +24,7 @@
 #include "nodes/extensible.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
+#include "optimizer/paths.h"
 #include "parser/analyze.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteHandler.h"
@@ -153,7 +154,7 @@ static void ExplainIndentText(ExplainState *es);
 static void ExplainJSONLineEnding(ExplainState *es);
 static void ExplainYAMLLineStarting(ExplainState *es);
 static void escape_yaml(StringInfo buf, const char *str);
-
+static void ExplainPrintGeqoDetails(ExplainState *es, QueryDesc *queryDesc);
 
 
 /*
@@ -190,6 +191,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt,
 			es->wal = defGetBoolean(opt);
 		else if (strcmp(opt->defname, "settings") == 0)
 			es->settings = defGetBoolean(opt);
+		else if (strcmp(opt->defname, "geqo") == 0)
+			es->geqo = defGetBoolean(opt);
 		else if (strcmp(opt->defname, "timing") == 0)
 		{
 			timing_set = true;
@@ -620,6 +623,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
 							   plannedstmt->queryId, es);
 	}
 
+	/* Print info about details option */
+	if (es->geqo)
+		ExplainPrintGeqoDetails(es, queryDesc);
+
 	/* Show buffer usage in planning */
 	if (bufusage)
 	{
@@ -742,6 +749,50 @@ ExplainPrintSettings(ExplainState *es)
 	}
 }
 
+void
+ExplainPrintGeqoDetails(ExplainState *es, QueryDesc *queryDesc)
+{
+	if (!enable_geqo)
+		return;
+
+	if (es->format != EXPLAIN_FORMAT_TEXT)
+	{
+		ExplainOpenGroup("GeqoDetails", "GeqoDetails", true, es);
+
+		if (queryDesc->plannedstmt->geqoFlag)
+			ExplainPropertyText("GEQO", "used", es);
+		else
+			ExplainPropertyText("GEQO", "not used", es);
+		ExplainPropertyInteger("geqo_threshold", NULL, geqo_threshold, es);
+
+		ExplainPropertyInteger("Max join nodes", NULL,
+								queryDesc->plannedstmt->max_nodes_in_join_search, es);
+
+		ExplainCloseGroup("GeqoDetails", "GeqoDetails", true, es);
+	}
+	else
+	{
+		StringInfoData str;
+
+		initStringInfo(&str);
+
+		if (queryDesc->plannedstmt->geqoFlag)
+			appendStringInfo(&str, "GEQO: used");
+		else
+			appendStringInfo(&str, "GEQO: not used");
+
+		appendStringInfoString(&str, ", ");
+		appendStringInfo(&str, "geqo_threshold: %d", geqo_threshold);
+
+		appendStringInfoString(&str, ", ");
+		appendStringInfo(&str, "Max join nodes: %d",
+					queryDesc->plannedstmt->max_nodes_in_join_search);
+
+		ExplainPropertyText("GeqoDetails", str.data, es);
+	}
+
+}
+
 /*
  * ExplainPrintPlan -
  *	  convert a QueryDesc's plan tree to text and append it to es->str
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d84f66a81b..417a16a97e 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -3237,6 +3237,9 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
 	if (levels_needed <= 0)
 		return NULL;			/* nothing to do? */
 
+	if (root->max_joinnodes < levels_needed)
+		root->max_joinnodes = levels_needed;
+
 	/*
 	 * Construct a list of rels corresponding to the child joinlist nodes.
 	 * This may contain both base rels and rels constructed according to
@@ -3290,7 +3293,12 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
 		if (join_search_hook)
 			return (*join_search_hook) (root, levels_needed, initial_rels);
 		else if (enable_geqo && levels_needed >= geqo_threshold)
+		{
+			elog(DEBUG1, "the number of join nodes %d is larger than geqo_threshold %d",
+				levels_needed, geqo_threshold);
+			root->geqo_used = true;
 			return geqo(root, levels_needed, initial_rels);
+		}
 		else
 			return standard_join_search(root, levels_needed, initial_rels);
 	}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 9a4accb4d9..3c061e52d6 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -532,6 +532,15 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 	result->stmt_location = parse->stmt_location;
 	result->stmt_len = parse->stmt_len;
 
+	result->geqoFlag = false;
+	result->max_nodes_in_join_search = 0;
+	if (enable_geqo)
+	{
+		result->geqoFlag = root->geqo_used;
+		result->max_nodes_in_join_search = root->max_joinnodes;
+	}
+
+
 	result->jitFlags = PGJIT_NONE;
 	if (jit_enabled && jit_above_cost >= 0 &&
 		top_plan->total_cost > jit_above_cost)
@@ -641,6 +650,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
 		root->wt_param_id = -1;
 	root->non_recursive_path = NULL;
 	root->partColsUpdated = false;
+	root->geqo_used = false;
+	root->max_joinnodes = 0;
 
 	/*
 	 * If there is a WITH list, process each WITH query and either convert it
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index 666977fb1f..f3e4ec95ee 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -46,6 +46,7 @@ typedef struct ExplainState
 	bool		timing;			/* print detailed node timing */
 	bool		summary;		/* print total planning and execution timing */
 	bool		settings;		/* print modified settings */
+	bool		geqo;			/* print geqo details */
 	ExplainFormat format;		/* output format */
 	/* state for output formatting --- not reset for each new plan tree */
 	int			indent;			/* current indentation level */
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 244d1e1197..6ecf3954c5 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -378,6 +378,10 @@ struct PlannerInfo
 
 	/* Does this query modify any partition key columns? */
 	bool		partColsUpdated;
+
+	/* Information about geqo */
+	bool		geqo_used;
+	int			max_joinnodes;
 };
 
 
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index e43e360d9b..89fd51d931 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -89,6 +89,9 @@ typedef struct PlannedStmt
 	/* statement location in source string (copied from Query) */
 	int			stmt_location;	/* start location, or -1 if unknown */
 	int			stmt_len;		/* length in bytes; 0 means "rest of string" */
+
+	bool		geqoFlag;		/* if true, geqo is used */
+	int			max_nodes_in_join_search;	/* the number of join nodes when geqo is used */
 } PlannedStmt;
 
 /* macro for fetching the Plan associated with a SubPlan node */
