diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 03a54451ac..e1b4a4f56b 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -128,6 +128,7 @@ int			IntervalStyle = INTSTYLE_POSTGRES;
 bool		enableFsync = true;
 bool		allowSystemTableMods = false;
 int			work_mem = 4096;
+int			debug_palloc_context_threshold = 0;
 double		hash_mem_multiplier = 2.0;
 int			maintenance_work_mem = 65536;
 int			max_parallel_maintenance_workers = 2;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 79ecaa4c4c..53ab643d3a 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -2508,6 +2508,18 @@ struct config_int ConfigureNamesInt[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"debug_palloc_context_threshold", PGC_USERSET, RESOURCES_MEM,
+			gettext_noop("Dump memory context usage stats when using more than this memory in context."),
+			gettext_noop("Dump MemoryContextStats() when palloc() ends up "
+						 "with more than context->mem_used than defined here"),
+			GUC_UNIT_KB
+		},
+		&debug_palloc_context_threshold,
+		0, 0, MAX_KILOBYTES,
+		NULL, NULL, NULL
+	},
+
 	/*
 	 * Dynamic shared memory has a higher overhead than local memory contexts,
 	 * so when testing low-memory scenarios that could use shared memory, the
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index bde54326c6..66959ab98c 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -27,6 +27,7 @@
 #include "utils/memutils.h"
 #include "utils/memutils_internal.h"
 #include "utils/memutils_memorychunk.h"
+#include "portability/instr_time.h"
 
 
 static void BogusFree(void *pointer);
@@ -156,6 +157,9 @@ MemoryContext CurTransactionContext = NULL;
 
 /* This is a transient link to the active portal's memory context: */
 MemoryContext PortalContext = NULL;
+/* Last timestamp when there was MemoryContextStats() dump by debug_palloc_context_threshold */
+static instr_time debug_palloc_context_last_ts;
+static int recursion_level = 0;
 
 static void MemoryContextDeleteOnly(MemoryContext context);
 static void MemoryContextCallResetCallbacks(MemoryContext context);
@@ -1313,6 +1317,43 @@ ProcessLogMemoryContextInterrupt(void)
 	MemoryContextStatsDetail(TopMemoryContext, 100, 100, false);
 }
 
+/*
+ * dump_memory_debug_if_necessary
+ *		Log using MemoryContextStats(), but not too often
+ *
+ */
+static void
+dump_memory_debug_if_necessary(MemoryContext context)
+{
+	/* We need to never recurse infinitley as some routines used later on
+	 * may also call palloc() internally.
+	 */
+	if(recursion_level >= 1)
+		return;
+	recursion_level++;
+
+	if (debug_palloc_context_threshold != 0 &&
+		context->mem_allocated * 1024 >= debug_palloc_context_threshold) {
+		instr_time now, ts_diff;
+		INSTR_TIME_SET_CURRENT(now);
+		ts_diff = now;
+		INSTR_TIME_SUBTRACT(ts_diff, debug_palloc_context_last_ts);
+
+#define MEMSTAT_DUMP_INTERVAL_MS 100
+		/* Rate limit the messages to avoid log clutter */
+		if ((double) INSTR_TIME_GET_MILLISEC(ts_diff) >= MEMSTAT_DUMP_INTERVAL_MS) {
+			ereport(LOG,
+				(errmsg("dumping memory context stats"),
+				 errdetail("Context \"%s\".", context->name),
+				 errbacktrace()));
+			MemoryContextStatsDetail(context, 100, 100, false);
+			debug_palloc_context_last_ts = now;
+		}
+	}
+
+	recursion_level--;
+}
+
 void *
 palloc(Size size)
 {
@@ -1340,6 +1381,8 @@ palloc(Size size)
 	Assert(ret != NULL);
 	VALGRIND_MEMPOOL_ALLOC(context, ret, size);
 
+	dump_memory_debug_if_necessary(context);
+
 	return ret;
 }
 
@@ -1361,6 +1404,8 @@ palloc0(Size size)
 
 	MemSetAligned(ret, 0, size);
 
+	dump_memory_debug_if_necessary(context);
+
 	return ret;
 }
 
@@ -1387,6 +1432,8 @@ palloc_extended(Size size, int flags)
 	if ((flags & MCXT_ALLOC_ZERO) != 0)
 		MemSetAligned(ret, 0, size);
 
+	dump_memory_debug_if_necessary(context);
+
 	return ret;
 }
 
@@ -1489,6 +1536,8 @@ MemoryContextAllocAligned(MemoryContext context,
 	/* Disallow access to the redirection chunk header. */
 	VALGRIND_MAKE_MEM_NOACCESS(alignedchunk, sizeof(MemoryChunk));
 
+	dump_memory_debug_if_necessary(context);
+
 	return aligned;
 }
 
@@ -1660,6 +1709,8 @@ MemoryContextAllocHuge(MemoryContext context, Size size)
 
 	VALGRIND_MEMPOOL_ALLOC(context, ret, size);
 
+	dump_memory_debug_if_necessary(context);
+
 	return ret;
 }
 
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 25348e71eb..cf17fbd22f 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -265,6 +265,7 @@ extern PGDLLIMPORT int IntervalStyle;
 extern PGDLLIMPORT bool enableFsync;
 extern PGDLLIMPORT bool allowSystemTableMods;
 extern PGDLLIMPORT int work_mem;
+extern PGDLLIMPORT int debug_palloc_context_threshold;
 extern PGDLLIMPORT double hash_mem_multiplier;
 extern PGDLLIMPORT int maintenance_work_mem;
 extern PGDLLIMPORT int max_parallel_maintenance_workers;
