diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 2b992d7832..4fb6ec60d4 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1179,6 +1179,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 		relation->rd_partkeycxt = NULL;
 		relation->rd_partdesc = NULL;
 		relation->rd_pdcxt = NULL;
+		relation->rd_pdoldcxt = NULL;
 	}
 	/* ... but partcheck is not loaded till asked for */
 	relation->rd_partcheck = NIL;
@@ -2073,6 +2074,11 @@ RelationDecrementReferenceCount(Relation rel)
 	rel->rd_refcnt -= 1;
 	if (!IsBootstrapProcessingMode())
 		ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel);
+	if (rel->rd_refcnt == 0 && rel->rd_pdoldcxt != NULL)
+	{
+		MemoryContextDelete(rel->rd_pdoldcxt);
+		rel->rd_pdoldcxt = NULL;
+	}
 }
 
 /*
@@ -2368,6 +2374,8 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
 		MemoryContextDelete(relation->rd_partkeycxt);
 	if (relation->rd_pdcxt)
 		MemoryContextDelete(relation->rd_pdcxt);
+	if (relation->rd_pdoldcxt)
+		MemoryContextDelete(relation->rd_pdoldcxt);
 	if (relation->rd_partcheckcxt)
 		MemoryContextDelete(relation->rd_partcheckcxt);
 	if (relation->rd_fdwroutine)
@@ -2622,6 +2630,7 @@ RelationClearRelation(Relation relation, bool rebuild)
 		{
 			SWAPFIELD(PartitionDesc, rd_partdesc);
 			SWAPFIELD(MemoryContext, rd_pdcxt);
+			SWAPFIELD(MemoryContext, rd_pdoldcxt);
 		}
 		else if (rebuild && newrel->rd_pdcxt != NULL)
 		{
@@ -2629,17 +2638,25 @@ RelationClearRelation(Relation relation, bool rebuild)
 			 * We are rebuilding a partitioned relation with a non-zero
 			 * reference count, so keep the old partition descriptor around,
 			 * in case there's a PartitionDirectory with a pointer to it.
-			 * Attach it to the new rd_pdcxt so that it gets cleaned up
-			 * eventually.  In the case where the reference count is 0, this
-			 * code is not reached, which should be OK because in that case
-			 * there should be no PartitionDirectory with a pointer to the old
-			 * entry.
+			 * In the case where the reference count is 0, this code is not
+			 * reached, which should be OK because in that case there should be
+			 * no PartitionDirectory with a pointer to the old entry.
+			 *
+			 * To avoid leaking memory, we've got to make sure that the next
+			 * time rd_pdoldcxt is destroyed, the old context will be freed.
+			 * If rd_pdoldcxt is NULL, we can just make it point to the
+			 * old descriptor's context; otherwise, we make this context of
+			 * the previous one.
 			 *
 			 * Note that newrel and relation have already been swapped, so the
 			 * "old" partition descriptor is actually the one hanging off of
 			 * newrel.
 			 */
-			MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt);
+			if (relation->rd_pdoldcxt == NULL)
+				relation->rd_pdoldcxt = newrel->rd_pdcxt;
+			else
+				MemoryContextSetParent(newrel->rd_pdcxt,
+									   relation->rd_pdoldcxt);
 			newrel->rd_partdesc = NULL;
 			newrel->rd_pdcxt = NULL;
 		}
@@ -5580,6 +5597,7 @@ load_relcache_init_file(bool shared)
 		rel->rd_partkeycxt = NULL;
 		rel->rd_partdesc = NULL;
 		rel->rd_pdcxt = NULL;
+		rel->rd_pdoldcxt = NULL;
 		rel->rd_partcheck = NIL;
 		rel->rd_partcheckvalid = false;
 		rel->rd_partcheckcxt = NULL;
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index d7f33abce3..09abcdf030 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -99,6 +99,7 @@ typedef struct RelationData
 	MemoryContext rd_partkeycxt;	/* private context for rd_partkey, if any */
 	struct PartitionDescData *rd_partdesc;	/* partitions, or NULL */
 	MemoryContext rd_pdcxt;		/* private context for rd_partdesc, if any */
+	MemoryContext rd_pdoldcxt;	/* context for older PartitionDescs, if any */
 	List	   *rd_partcheck;	/* partition CHECK quals */
 	bool		rd_partcheckvalid;	/* true if list has been computed */
 	MemoryContext rd_partcheckcxt;	/* private cxt for rd_partcheck, if any */
