diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 628d6f5..eeb6a82 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -213,6 +213,8 @@ static struct RELCACHECALLBACK
 
 static int	relcache_callback_count = 0;
 
+int invalidate_all_threshold = 0; /* GUC */
+
 /* ----------------------------------------------------------------
  *				Invalidation list support functions
  *
@@ -287,6 +289,81 @@ AppendInvalidationMessageList(InvalidationChunk **destHdr,
 	*destHdr = *srcHdr;
 
 	*srcHdr = NULL;
+
+	if (invalidate_all_threshold > 0)
+	{
+		int n_invalidations = 0;
+
+		/* Count total number of message */
+		for (chunk = *destHdr; chunk != NULL; chunk = chunk->next)
+			n_invalidations += chunk->nitems;
+
+		if (n_invalidations > invalidate_all_threshold)
+		{
+			/* Replace all individual invalidation messages with reset-all ones */
+			InvalidationChunk *tail = *destHdr;
+			int n_tail_msgs = 0;
+			int mask = 0;
+
+			for (chunk = tail; chunk != NULL; chunk = chunk->next)
+			{
+				for (int i = 0; i < chunk->nitems; i++)
+				{
+					switch (chunk->msgs[i].id)
+					{
+					  case SHAREDINVALCATALOG_ID:
+						if (!(mask & (1 << -SHAREDINVALCATALOG_ID)))
+						{
+							tail->msgs[n_tail_msgs].id = SHAREDINVALCATALOG_ID;
+							tail->msgs[n_tail_msgs].cat.dbId = InvalidOid;
+							n_tail_msgs += 1;
+							mask |= (1 << -SHAREDINVALCATALOG_ID);
+						}
+						break;
+					  case SHAREDINVALRELCACHE_ID:
+						if (!(mask & (1 << -SHAREDINVALRELCACHE_ID)))
+						{
+							tail->msgs[n_tail_msgs].id = SHAREDINVALRELCACHE_ID;
+							tail->msgs[n_tail_msgs].rc.dbId = InvalidOid;
+							tail->msgs[n_tail_msgs].rc.relId = InvalidOid;
+							n_tail_msgs += 1;
+							mask |= (1 << -SHAREDINVALRELCACHE_ID);
+						}
+						break;
+					  case SHAREDINVALSNAPSHOT_ID:
+						if (!(mask & (1 << -SHAREDINVALSNAPSHOT_ID)))
+						{
+							tail->msgs[n_tail_msgs].id = SHAREDINVALSNAPSHOT_ID;
+							tail->msgs[n_tail_msgs].sn.dbId = InvalidOid;
+							tail->msgs[n_tail_msgs].sn.relId = InvalidOid;
+							n_tail_msgs += 1;
+							mask |= (1 << -SHAREDINVALSNAPSHOT_ID);
+						}
+						break;
+					  default:
+						tail->msgs[n_tail_msgs++] = chunk->msgs[i];
+					}
+					if (n_tail_msgs == tail->maxitems)
+					{
+						tail->nitems = n_tail_msgs;
+						tail = tail->next;
+						n_tail_msgs = 0;
+					}
+				}
+			}
+			tail->nitems = n_tail_msgs;
+
+			/* remove rest of chain */
+			chunk = tail->next;
+			tail->next = NULL;
+			while (chunk != NULL)
+			{
+				tail = chunk->next;
+				pfree(chunk);
+				chunk = tail;
+			}
+		}
+	}
 }
 
 /*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 878fcc2..b9bf525 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -90,6 +90,7 @@
 #include "utils/bytea.h"
 #include "utils/float.h"
 #include "utils/guc_tables.h"
+#include "utils/inval.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/pg_lsn.h"
@@ -2348,6 +2349,16 @@ static struct config_int ConfigureNamesInt[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"invalidate_all_threshold", PGC_SUSET, RESOURCES_MEM,
+			gettext_noop("Limit for maximal number of invalidation messages after reaching which all system caches are invalidateds."),
+			NULL
+		},
+		&invalidate_all_threshold,
+		0, 0, INT_MAX,
+		check_max_stack_depth, assign_max_stack_depth, NULL
+	},
+
 	/*
 	 * We use the hopefully-safely-small value of 100kB as the compiled-in
 	 * default for max_stack_depth.  InitializeGUCOptions will increase it if
diff --git a/src/include/utils/inval.h b/src/include/utils/inval.h
index 463888c..e59d338 100644
--- a/src/include/utils/inval.h
+++ b/src/include/utils/inval.h
@@ -22,6 +22,7 @@
 typedef void (*SyscacheCallbackFunction) (Datum arg, int cacheid, uint32 hashvalue);
 typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid);
 
+extern int invalidate_all_threshold;
 
 extern void AcceptInvalidationMessages(void);
 
