PostgreSQLXVII · Capacity, Maintenance and UpgradesMaintenance
Upgrade rehearsal and post-upgrade validation
What you'll learn
- Rehearse an upgrade in a way that produces a usable duration
- Validate an upgraded cluster beyond "it started"
- Plan a rollback appropriate to the transfer mode
- Decide the go/no-go criteria before the window opens
Prerequisites
Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27
An upgrade you have not rehearsed is a procedure you are testing on production, with an audience.
Rehearsing
On a restored copy of production. Not a subset, not a schema-only copy, not staging with a thousandth of the rows. The duration you need depends on the data volume and on the number of objects, and neither transfers from a smaller copy.
This is also, usefully, a restore test — lesson XIII-08’s requirement, satisfied by an exercise you were doing anyway.
With the real procedure, from the written runbook. If the runbook is wrong, the rehearsal should discover that.
Measure four things:
| Number | Why |
|---|---|
| Wall-clock, stop to accepting connections | Your window |
Wall-clock of the ANALYZE afterwards | Often longer than the upgrade |
What --check reported | The problems, before the window |
| What broke afterwards | The list you would otherwise find live |
Validating
“It started” is not validation. Four levels, and the last two are the ones that get skipped.
1. It is running the version you expect
SELECT version();
2. The data is there
-- row counts per table, compared against the same query before
SELECT relname, n_live_tup FROM pg_stat_user_tables ORDER BY relname;
That view is empty immediately after an upgrade — lesson XVII-07
measured n_live_tup at zero — so run ANALYZE first, or count
directly:
SELECT count(*) FROM orders;
Take these counts before the upgrade too. A comparison needs both sides.
3. The application works
Its own test suite, against the upgraded cluster. Not a sample of queries somebody wrote for the occasion.
4. The plans have not changed catastrophically
This is the one that is skipped and the one that causes the “the upgrade made everything slow” incident.
-- capture before, on the old cluster
EXPLAIN (FORMAT JSON) <your top 20 queries by total_exec_time>;
-- capture after, on the new one, and diff
Take the top 20 from pg_stat_statements on the old cluster, capture
their plans on both, and compare. A planner change between major
versions is a feature; discovering it in production is not.
The rollback
The plan depends entirely on the transfer mode, and must be decided before the window:
| Mode | Rollback |
|---|---|
| Dump/restore | Start the old cluster. Minutes |
pg_upgrade --copy | Start the old cluster. Minutes |
pg_upgrade --link / --swap | Restore from backup. Hours |
| Logical replication | Switch the application back. Seconds |
Go/no-go, decided in advance
Write these down before the window opens, because deciding them inside it is how a bad upgrade gets accepted:
- Abort if
--checkreports anything unresolved. - Abort if the verified backup is not verified.
- Abort if the rehearsal’s duration exceeded the window.
- Roll back if row counts do not match.
- Roll back if the application test suite fails.
- Investigate, do not roll back, if a few plans changed — that is expected, and rolling back for it means never upgrading.
The last one matters as much as the others. A team that rolls back on any regression will defer major upgrades indefinitely, and end up doing four versions at once on an unsupported release, which is strictly worse.
What to take from this
- Rehearse on a restored copy of production, with the real procedure. It doubles as a restore test.
- The rehearsal produces your duration. This course’s 2 seconds is a mechanism, not a projection.
- Validate on four levels: version, data, application, plans.
- PostgreSQL 18 carries planner statistics across, which removes most of the post-upgrade slowness — not the plan changes.
- The rollback depends on transfer mode.
--linkand--swapmean restore from backup. - Do not run
delete_old_cluster.shon the day. - Decide go/no-go criteria in advance, and do not roll back for a few changed plans.
- Plan the outer window too: rebuilding standbys and taking a new backup, during which the cluster is unprotected.
Cross-course references
- Linux for Production Sysadmins — Part LXIV (Rolling maintenance) covers rehearsing on production-scale data so the window is sized from a measurement, and Part LXXXIII (Operational documentation) covers recording the timings for the next one.
- Git, CI/CD & GitOps — Part LXIV (Auditability) covers keeping the before-and-after evidence that makes “the upgrade worked” a claim somebody else can check.
Quiz
Knowledge check · 6 questions
Q1. A database with 50,000 tables and partitions but only 200 GB of data takes far longer to pg_upgrade than a 5 TB database with ten tables. Why?
Q2. Why does comparing query plans before and after a major upgrade remain worthwhile on PostgreSQL 18, given that planner statistics now transfer?
Q3. An upgrade plan allocates a two-hour window for a large cluster and declares success when the application reconnects. What has it omitted?
Q4. What should an upgrade rehearsal measure or produce? Select all that apply.
Q5. A team that rolls back a major upgrade whenever any query plan regresses is following good practice.
Q6. What must a major upgrade rehearsal include for its duration to be trustworthy?
Passing score: 75%. Answers are checked in this browser.