diff --git a/contrib/pg_upgrade/dump.c b/contrib/pg_upgrade/dump.c
index b112f3a95276e7eea538494de1d16f10bcf3573a..e623a2263277262fd15a52671df4ae2f89431907 100644
--- a/contrib/pg_upgrade/dump.c
+++ b/contrib/pg_upgrade/dump.c
@@ -12,6 +12,8 @@
 #include "pg_upgrade.h"
 
 #include <sys/types.h>
+#include "catalog/binary_upgrade.h"
+
 
 void
 generate_old_dump(void)
@@ -67,3 +69,71 @@ generate_old_dump(void)
 	end_progress_output();
 	check_ok();
 }
+
+
+/*
+ * It is possible for there to be a mismatch in the need for TOAST tables
+ * between the old and new servers, e.g. some pre-9.1 tables didn't need
+ * TOAST tables but will need them in 9.1+.  (There are also opposite cases,
+ * but these are handled by setting binary_upgrade_next_toast_pg_class_oid.)
+ *
+ * We can't allow the TOAST table to be created by pg_dump with a
+ * pg_dump-assigned oid because it might conflict with a later table that
+ * uses that oid, causing a "file exists" error for pg_class conflicts, and
+ * a "duplicate oid" error for pg_type conflicts.  (TOAST tables need pg_type
+ * entries.)
+ *
+ * Therefore, a backend in binary-upgrade mode will not create a TOAST
+ * table unless an OID as passed in via pg_upgrade_support functions.
+ * This function is called after the restore and uses ALTER TABLE to
+ * auto-create any needed TOAST tables which will not conflict with
+ * restored oids.
+ */
+void
+optionally_create_toast_tables(void)
+{
+	int			dbnum;
+
+	prep_status("Creating newly-required TOAST tables");
+
+	for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
+	{
+		PGresult   *res;
+		int			ntups;
+		int			rowno;
+		int			i_nspname,
+					i_relname;
+		DbInfo	   *active_db = &new_cluster.dbarr.dbs[dbnum];
+		PGconn	   *conn = connectToServer(&new_cluster, active_db->db_name);
+
+		res = executeQueryOrDie(conn,
+								"SELECT n.nspname, c.relname "
+								"FROM	pg_catalog.pg_class c, "
+								"		pg_catalog.pg_namespace n "
+								"WHERE	c.relnamespace = n.oid AND "
+							  "		n.nspname NOT IN ('pg_catalog', 'information_schema') AND "
+								"c.relkind IN ('r', 'm') AND "
+								"c.reltoastrelid = 0");
+
+		ntups = PQntuples(res);
+		i_nspname = PQfnumber(res, "nspname");
+		i_relname = PQfnumber(res, "relname");
+		for (rowno = 0; rowno < ntups; rowno++)
+		{
+			/* enable auto-oid-numbered TOAST creation if needed */
+			PQclear(executeQueryOrDie(conn, "SELECT binary_upgrade.set_next_toast_pg_class_oid('%d'::pg_catalog.oid);",
+					OPTIONALLY_CREATE_TOAST_OID));
+
+			/* dummy command that also triggers check for required TOAST table */
+			PQclear(executeQueryOrDie(conn, "ALTER TABLE %s.%s RESET (binary_upgrade_dummy_option);",
+					quote_identifier(PQgetvalue(res, rowno, i_nspname)),
+					quote_identifier(PQgetvalue(res, rowno, i_relname))));
+		}
+
+		PQclear(res);
+
+		PQfinish(conn);
+	}
+
+	check_ok();
+}
diff --git a/contrib/pg_upgrade/pg_upgrade.c b/contrib/pg_upgrade/pg_upgrade.c
index 3e97b66476fa7d8e938a0fe9fb0525a8bd2f09c3..49ea873099d9e3f5e952b7b5e1eb44f7adfcc1ba 100644
--- a/contrib/pg_upgrade/pg_upgrade.c
+++ b/contrib/pg_upgrade/pg_upgrade.c
@@ -363,6 +363,8 @@ create_new_objects(void)
 	if (GET_MAJOR_VERSION(old_cluster.major_version) < 903)
 		set_frozenxids(true);
 
+	optionally_create_toast_tables();
+
 	/* regenerate now that we have objects in the databases */
 	get_db_and_rel_infos(&new_cluster);
 
diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h
index 61e5de015ca76756d0a9c7c2f849ad12b6032d94..1175604e3751aba7a207c6e034f3ca05491f1c0b 100644
--- a/contrib/pg_upgrade/pg_upgrade.h
+++ b/contrib/pg_upgrade/pg_upgrade.h
@@ -336,6 +336,7 @@ void		disable_old_cluster(void);
 /* dump.c */
 
 void		generate_old_dump(void);
+void		optionally_create_toast_tables(void);
 
 
 /* exec.c */
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index bdfeb90dd109196aa6c3402cb1f15c9cc6a63df1..94543e1d51023df5351f44414a5a39a2480fac0f 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -165,16 +165,51 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 	if (rel->rd_rel->reltoastrelid != InvalidOid)
 		return false;
 
-	/*
-	 * Check to see whether the table actually needs a TOAST table.
-	 *
-	 * If an update-in-place toast relfilenode is specified, force toast file
-	 * creation even if it seems not to need one.
-	 */
-	if (!needs_toast_table(rel) &&
-		(!IsBinaryUpgrade ||
-		 !OidIsValid(binary_upgrade_next_toast_pg_class_oid)))
-		return false;
+	if (!IsBinaryUpgrade)
+	{
+		if (!needs_toast_table(rel))
+			return false;
+	}
+	else
+	{
+		/*
+		 * Check to see whether the table needs a TOAST table.
+		 *
+		 * If an update-in-place TOAST relfilenode is specified, force TOAST file
+		 * creation even if it seems not to need one.  This handles the case
+		 * where the old cluster needed a TOAST table but the new cluster
+		 * would not normally create one.
+		 */
+
+		/*
+		 * If a TOAST oid is not specified, skip TOAST creation as we will do
+		 * it later so we don't create a TOAST table whose OID later conflicts
+		 * with a user-supplied OID.  This handles cases where the old cluster
+		 * didn't need a TOAST table, but the new cluster does.
+		 */
+		if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid))
+			return false;
+
+		/*
+		 * If a special TOAST value has been passed in, it means we are in
+		 * cleanup mode --- we are creating needed TOAST tables after all user
+		 * tables with specified OIDs have been created.  We let the system
+		 * assign a TOAST oid for us.  The tables are empty so the missing
+		 * TOAST tables were not a problem.
+		 */
+		if (binary_upgrade_next_toast_pg_class_oid == OPTIONALLY_CREATE_TOAST_OID)
+		{
+			/* clear as it is not to be used; it is just a flag */
+			binary_upgrade_next_toast_pg_class_oid = InvalidOid;
+
+			if (!needs_toast_table(rel))
+				return false;
+		}
+
+		/* both should be set, or not set */
+		Assert(OidIsValid(binary_upgrade_next_toast_pg_class_oid) ==
+			   OidIsValid(binary_upgrade_next_toast_pg_type_oid));
+	}
 
 	/*
 	 * If requested check lockmode is sufficient. This is a cross check in
diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h
index f39017cfdf01f5c747a1982a798df001956f9394..63fa85ed99ecde5e698656ed619f5cce557f241f 100644
--- a/src/include/catalog/binary_upgrade.h
+++ b/src/include/catalog/binary_upgrade.h
@@ -14,6 +14,11 @@
 #ifndef BINARY_UPGRADE_H
 #define BINARY_UPGRADE_H
 
+#include "catalog/pg_authid.h"
+
+/* pick a OID that will never be used for TOAST tables */
+#define OPTIONALLY_CREATE_TOAST_OID	BOOTSTRAP_SUPERUSERID
+
 extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid;
 extern PGDLLIMPORT Oid binary_upgrade_next_array_pg_type_oid;
 extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_type_oid;