Skip to main content
RunBook Academy

PostgreSQLXVII · Capacity, Maintenance and UpgradesMaintenance

Upgrade rehearsal and post-upgrade validation

Intermediate⏱ ~30 min🧪 Lab requiredpg_upgradepsql

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

Not yet marked complete on this device.

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:

NumberWhy
Wall-clock, stop to accepting connectionsYour window
Wall-clock of the ANALYZE afterwardsOften longer than the upgrade
What --check reportedThe problems, before the window
What broke afterwardsThe 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:

ModeRollback
Dump/restoreStart the old cluster. Minutes
pg_upgrade --copyStart the old cluster. Minutes
pg_upgrade --link / --swapRestore from backup. Hours
Logical replicationSwitch 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 --check reports 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. --link and --swap mean restore from backup.
  • Do not run delete_old_cluster.sh on 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

  1. 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?

  2. Q2. Why does comparing query plans before and after a major upgrade remain worthwhile on PostgreSQL 18, given that planner statistics now transfer?

  3. Q3. An upgrade plan allocates a two-hour window for a large cluster and declares success when the application reconnects. What has it omitted?

  4. Q4. What should an upgrade rehearsal measure or produce? Select all that apply.

  5. Q5. A team that rolls back a major upgrade whenever any query plan regresses is following good practice.

  6. Q6. What must a major upgrade rehearsal include for its duration to be trustworthy?

Passing score: 75%. Answers are checked in this browser.