diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index e3a6911..240d1b6 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -130,6 +130,17 @@ int			Log_autovacuum_min_duration = -1;
 #define MIN_AUTOVAC_SLEEPTIME 100.0		/* milliseconds */
 #define MAX_AUTOVAC_SLEEPTIME 300		/* seconds */
 
+/*
+ * Maximum number of orphan temporary tables to accumulate before switching
+ * to a new transaction when dropping them.
+ */
+#define MAX_ORPHAN_ITEMS		50
+/*
+ * Maximum number of attempts until giving up the drop of temporary orphan
+ * tables.
+ */
+#define MAX_ORPHAN_DROP_FAILURE	10
+
 /* Flags to tell if we are in an autovacuum process */
 static bool am_autovacuum_launcher = false;
 static bool am_autovacuum_worker = false;
@@ -1887,6 +1898,8 @@ do_autovacuum(void)
 	HeapScanDesc relScan;
 	Form_pg_database dbForm;
 	List	   *table_oids = NIL;
+	List	   *orphan_oids = NIL;
+	List	   *pending_oids = NIL;
 	HASHCTL		ctl;
 	HTAB	   *table_toast_map;
 	ListCell   *volatile cell;
@@ -1895,6 +1908,7 @@ do_autovacuum(void)
 	BufferAccessStrategy bstrategy;
 	ScanKeyData key;
 	TupleDesc	pg_class_desc;
+	int			orphan_failures;
 	int			effective_multixact_freeze_max_age;
 
 	/*
@@ -2038,33 +2052,11 @@ do_autovacuum(void)
 			if (backendID == MyBackendId || BackendIdGetProc(backendID) == NULL)
 			{
 				/*
-				 * We found an orphan temp table (which was probably left
-				 * behind by a crashed backend).  If it's so old as to need
-				 * vacuum for wraparound, forcibly drop it.  Otherwise just
-				 * log a complaint.
+				 * We found an orphan temp table which was probably left
+				 * behind by a crashed backend, store it to attempt a drop
+				 * in next phase.
 				 */
-				if (wraparound)
-				{
-					ObjectAddress object;
-
-					ereport(LOG,
-							(errmsg("autovacuum: dropping orphan temp table \"%s\".\"%s\" in database \"%s\"",
-								 get_namespace_name(classForm->relnamespace),
-									NameStr(classForm->relname),
-									get_database_name(MyDatabaseId))));
-					object.classId = RelationRelationId;
-					object.objectId = relid;
-					object.objectSubId = 0;
-					performDeletion(&object, DROP_CASCADE, PERFORM_DELETION_INTERNAL);
-				}
-				else
-				{
-					ereport(LOG,
-							(errmsg("autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"",
-								 get_namespace_name(classForm->relnamespace),
-									NameStr(classForm->relname),
-									get_database_name(MyDatabaseId))));
-				}
+				orphan_oids = lappend_oid(orphan_oids, relid);
 			}
 		}
 		else
@@ -2162,6 +2154,119 @@ do_autovacuum(void)
 	heap_close(classRel, AccessShareLock);
 
 	/*
+	 * Perform actual deletion of orphan temporary tables.  Deletion of
+	 * all the objects happens in a batch of transactions upper-bounded by
+	 * MAX_ORPHAN_ITEMS as maximum number of orphan temp tables removed
+	 * at once  to avoid transaction lock bloat because of too many objects
+	 * dropped in a single transaction.  If too many failures happen, just
+	 * give up and move to the next step to not influence autovacuum.
+	 */
+	while (list_length(orphan_oids) > 0 &&
+		   orphan_failures < MAX_ORPHAN_DROP_FAILURE)
+	{
+		Oid				relid = linitial_oid(orphan_oids);
+		ObjectAddress	object;
+		char		   *namespace = get_namespace_name(get_rel_namespace(relid));
+		char		   *relname = get_rel_name(relid);
+
+		orphan_oids = list_delete_first(orphan_oids);
+
+		PG_TRY();
+		{
+			ereport(LOG,
+					(errmsg("autovacuum: dropping orphan temp table \"%s\".\"%s\" in database \"%s\"",
+							namespace, relname,
+							get_database_name(MyDatabaseId))));
+			object.classId = RelationRelationId;
+			object.objectId = relid;
+			object.objectSubId = 0;
+			performDeletion(&object, DROP_CASCADE, PERFORM_DELETION_INTERNAL);
+
+			/*
+			 * This orphan table has been dropped correctly, add it to the
+			 * list of tables whose drop should be attempted again if an
+			 * error after in the same transaction.
+			 */
+			pending_oids = lappend_oid(pending_oids, relid);
+		}
+		PG_CATCH();
+		{
+			/*
+			 * Abort the current transaction and start a new one.  The next
+			 * batch will include any objects dropped in this one until this
+			 * failure and retry them.
+			 */
+			HOLD_INTERRUPTS();
+
+			errcontext("dropping of orphan temp table \"%s\".\"%s\" in database \"%s\"",
+					   namespace, relname,
+					   get_database_name(MyDatabaseId));
+
+			EmitErrorReport();
+
+			/* this resets the PGXACT flags too */
+			AbortOutOfAnyTransaction();
+			FlushErrorState();
+
+			/*
+			 * Add pending objects back to main list of orphan temporary
+			 * tables to drop, note that the one on which failure has just
+			 * happened is not appended back to it.
+			 */
+			orphan_oids = list_concat(orphan_oids, pending_oids);
+
+			orphan_failures++;
+
+			/* restart a transaction for the next batch of drops */
+			StartTransactionCommand();
+
+			/* StartTransactionCommand changed elsewhere the memory context */
+			MemoryContextSwitchTo(AutovacMemCxt);
+
+			RESUME_INTERRUPTS();
+		}
+		PG_END_TRY();
+
+		/*
+		 * If the pending list is full, commit the current transaction and
+		 * begin a new one.  All the existing pending items are now free
+		 * to rest in peace.
+		 */
+		if (list_length(pending_oids) >= MAX_ORPHAN_ITEMS)
+		{
+			CommitTransactionCommand();
+			StartTransactionCommand();
+
+			/* StartTransactionCommand changed elsewhere */
+			MemoryContextSwitchTo(AutovacMemCxt);
+
+			list_free(pending_oids);
+			pending_oids = NIL;
+		}
+
+		pfree(relname);
+		pfree(namespace);
+	}
+
+	/*
+	 * Commit current transaction to finish the cleanup done previously and
+	 * restart a new one to not bloat the activity of the following steps.
+	 * This needs to happen only if there are any items thought as previously
+	 * pending, but are actually not as the last transaction doing the cleanup
+	 * has been successful.
+	 */
+	if (list_length(pending_oids) > 0)
+	{
+		CommitTransactionCommand();
+		StartTransactionCommand();
+
+		/* StartTransactionCommand changed elsewhere */
+		MemoryContextSwitchTo(AutovacMemCxt);
+
+		list_free(pending_oids);
+	}
+
+	/*
 	 * Create a buffer access strategy object for VACUUM to use.  We want to
 	 * use the same one across all the vacuum operations we perform, since the
 	 * point is for VACUUM not to blow out the shared cache.
