Now that I've gotten your attention.. I expect pg_upgrade to fail if I run it twice in a row.
It would be reasonable if it were to fail during the "--check" phase, maybe by failing like this: | New cluster database "..." is not empty: found relation "..." But that fails to happen if the cluster has neither tables nor matviews, in which case, it passes the check phase and then fails like this: Performing Upgrade ------------------ Analyzing all rows in the new cluster ok Freezing all rows in the new cluster ok Deleting files from new pg_xact ok Copying old pg_clog to new server ok Setting oldest XID for new cluster ok Setting next transaction ID and epoch for new cluster ok Deleting files from new pg_multixact/offsets ok Copying old pg_multixact/offsets to new server ok Deleting files from new pg_multixact/members ok Copying old pg_multixact/members to new server ok Setting next multixact ID and offset for new cluster ok Resetting WAL archives ok Setting frozenxid and minmxid counters in new cluster connection to server on socket "/home/pryzbyj/src/postgres/.s.PGSQL.50432" failed: FATAL: could not open relation with OID 2610 Failure, exiting I'll concede that a cluster which has no tables sounds a lot like a toy, but I find it disturbing that nothing prevents running the process twice, up to the point that it's evidently corrupted the catalog. While looking at this, I noticed that starting postgres --single immediately after initdb allows creating objects with OIDs below FirstNormalObjectId (thereby defeating pg_upgrade's check). I'm not familiar with the behavioral differences of single user mode, and couldn't find anything in the documentation.