diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d2b15a3387..9f3f200e7b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3594,6 +3594,10 @@ CheckTableNotInUse(Relation rel, const char *stmt)
 		/* translator: first %s is a SQL command, eg ALTER TABLE */
 				 errmsg("cannot %s \"%s\" because it has pending trigger events",
 						stmt, RelationGetRelationName(rel))));
+
+	/* Mark the relation to disallow re-entrant access */
+	Assert(rel->rd_exclusive == NULL);
+	rel->rd_exclusive = stmt;
 }
 
 /*
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index a2453cf1f4..beff48accf 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1095,6 +1095,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	 * new relations, it won't be new.  It could be temp though.
 	 */
 	relation->rd_refcnt = 0;
+	relation->rd_exclusive = NULL;
 	relation->rd_isnailed = false;
 	relation->rd_createSubid = InvalidSubTransactionId;
 	relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
@@ -2069,6 +2070,9 @@ RelationIdGetRelation(Oid relationId)
 void
 RelationIncrementReferenceCount(Relation rel)
 {
+	if (rel->rd_exclusive)
+		elog(ERROR, "relation %s already in use by %s",
+			 RelationGetRelationName(rel), rel->rd_exclusive);
 	ResourceOwnerEnlargeRelationRefs(CurrentResourceOwner);
 	rel->rd_refcnt += 1;
 	if (!IsBootstrapProcessingMode())
@@ -2086,6 +2090,8 @@ RelationDecrementReferenceCount(Relation rel)
 	rel->rd_refcnt -= 1;
 	if (!IsBootstrapProcessingMode())
 		ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel);
+	if (rel->rd_refcnt == 0)
+		rel->rd_exclusive = NULL;
 }
 
 /*
@@ -2617,8 +2623,9 @@ RelationClearRelation(Relation relation, bool rebuild)
 
 		/* rd_smgr must not be swapped, due to back-links from smgr level */
 		SWAPFIELD(SMgrRelation, rd_smgr);
-		/* rd_refcnt must be preserved */
+		/* rd_refcnt and rd_exclusive must be preserved */
 		SWAPFIELD(int, rd_refcnt);
+		SWAPFIELD(const char *, rd_exclusive);
 		/* isnailed shouldn't change */
 		Assert(newrel->rd_isnailed == relation->rd_isnailed);
 		/* creation sub-XIDs must be preserved */
@@ -5917,6 +5924,7 @@ load_relcache_init_file(bool shared)
 			rel->rd_refcnt = 1;
 		else
 			rel->rd_refcnt = 0;
+		rel->rd_exclusive = NULL;
 		rel->rd_indexvalid = false;
 		rel->rd_indexlist = NIL;
 		rel->rd_pkindex = InvalidOid;
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 0b5957ba02..22cf7d4e70 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -57,6 +57,7 @@ typedef struct RelationData
 	struct SMgrRelationData *rd_smgr;	/* cached file handle, or NULL */
 	int			rd_refcnt;		/* reference count */
 	BackendId	rd_backend;		/* owning backend id, if temporary relation */
+	const char *rd_exclusive;	/* if not NULL, disallow re-entrant access */
 	bool		rd_islocaltemp; /* rel is a temp rel of this session */
 	bool		rd_isnailed;	/* rel is nailed in cache */
 	bool		rd_isvalid;		/* relcache entry is valid */
