Home / Alt manpages / pg_upgradecluster(1)

  • pg_upgradecluster(1)
  • User command
  • linux

Upgrade a Debian PostgreSQL Cluster with pg_upgradecluster

You will finish with a controlled major-version upgrade plan for a Debian PostgreSQL cluster, including a pre-flight inventory, a chosen migration method, post-upgrade checks and a recovery path that keeps the old cluster available. The examples match postgresql-common 257build1.1, installed on this system.

Allow at least thirty minutes for a small test cluster. A production cluster may take much longer, especially with the default dump and restore method. You need a root-capable maintenance shell, enough disk space for a second cluster or its temporary files, a tested backup, and a maintenance window. This command stops or changes cluster services, so do not run it against a production cluster without an agreed outage and rollback plan.

1. Inventory the cluster before changing anything

Run the inventory as an ordinary user first. pg_lsclusters shows the PostgreSQL major version, cluster name, port, state, owner, data directory and log file. Those values form the two positional arguments for the upgrade:

$ pg_lsclusters
Ver Cluster Port Status Owner    Data directory              Log file
16  main    5432 online postgres /var/lib/postgresql/16/main /var/log/postgresql/postgresql-16-main.log

In this example, 16 is the old version and main is the cluster name. Replace both with the values from your host. Do not assume that main exists, and do not confuse a PostgreSQL major version with a package revision.

Checkpoint: record the output, confirm the cluster is the one you intend to migrate, and make sure your backup can be restored. Also check available space in the old and new data locations. An upgrade creates a second cluster and can fail part-way through if storage runs out.

2. Choose the destination and method

The basic form is:

sudo pg_upgradecluster -v NEW_VERSION OLD_VERSION CLUSTER_NAME

The -v option names the new PostgreSQL major version. If you omit it, pg_upgradecluster selects the latest available version, which is convenient only when that choice is deliberate. The destination data directory defaults to /var/lib/postgresql/NEW_VERSION/CLUSTER_NAME. Pass a final directory argument when the new cluster belongs elsewhere:

sudo pg_upgradecluster -v 17 16 main /srv/postgresql/17/main

That is an operational example, not a command to paste unchanged. Check that the target server and its client or common package are installed, and use the actual version offered by your repository.

The default method is dump. It uses pg_dump and pg_restore, so it is usually the easiest method to reason about but can be slow. The upgrade method uses pg_upgrade. link is shorthand for upgrade with hard links, while clone uses filesystem cloning when supported:

sudo pg_upgradecluster -v NEW_VERSION -m upgrade OLD_VERSION CLUSTER_NAME
sudo pg_upgradecluster -v NEW_VERSION -m link OLD_VERSION CLUSTER_NAME
sudo pg_upgradecluster -v NEW_VERSION -m clone OLD_VERSION CLUSTER_NAME

Hard-link and clone choices have different storage and rollback implications. Read the installed pg_upgrade documentation and test the selected method on a representative copy before using it for an important database. Do not choose link because it looks faster without understanding what happens to the old data files.

3. Check configuration and extension hooks

pg_upgradecluster copies the old configuration into the new cluster and adjusts it for the new version. It inherits the old locale unless you provide --locale or one of the individual locale options. A locale change is a data and index compatibility decision, not a cosmetic setting; only request one when you have tested the consequences.

PostgreSQL extensions can require upgrade work before or after the data migration. pg_upgradecluster runs executable hook scripts from /etc/postgresql-common/pg_upgradecluster.d/. Their names may contain letters, digits, underscores and hyphens, but not dots. They receive:

OLD_VERSION CLUSTER_NAME NEW_VERSION PHASE

The init phase has a new, empty cluster containing template1 and postgres. The finish phase runs after the data has been copied or restored, while the old cluster is stopped. A failing hook aborts the upgrade, and hooks run as the database owner. Review these scripts before scheduling the migration, especially on a host using PostGIS or another extension with auxiliary metadata.

Do not create application tables in an init hook. The dump, restore or pg_upgrade operation will overwrite that work.

4. Run the upgrade during the maintenance window

Stop application writers, confirm that clients have drained, and take a final backup according to your normal procedure. Then run the chosen command with elevated privileges:

sudo pg_upgradecluster -v NEW_VERSION OLD_VERSION CLUSTER_NAME

By default, the new cluster takes the old cluster's original port. The old cluster is assigned a previously unused port and is put into manual startup mode. This is a deliberate safety boundary: old data remains available for checks, but the old cluster will not start automatically at boot.

Warning

The command changes ports, cluster state and service availability. Do not use --keep-port casually. It disables the normal port swap, so clients may continue to reach the old cluster or fail to find the new one unless you have a separate connection plan.

The default start behaviour starts the new cluster when the old one was running, or when upgrade hooks are present. Use --no-start when your deployment requires an explicit review before starting the new server:

sudo pg_upgradecluster -v NEW_VERSION --no-start OLD_VERSION CLUSTER_NAME

If the upgrade fails, the newly created cluster is normally removed. Add --keep-on-error only when you need the failed target for investigation and have enough space to retain it. Treat that retained directory as temporary diagnostic state, not as a usable database.

5. Verify the new cluster and application connections

Start with the cluster inventory. This is read-only and can be run without root:

$ pg_lsclusters
Ver Cluster Port Status Owner    Data directory              Log file
16  main    5433 manual postgres /var/lib/postgresql/16/main /var/log/postgresql/postgresql-16-main.log
17  main    5432 online  postgres /var/lib/postgresql/17/main /var/log/postgresql/postgresql-17-main.log

The exact port and status depend on your host. Confirm that the new version is online, the intended port is serving it, and the old version is present on its reassigned port or marked manual. Then connect explicitly to the new port rather than relying on a remembered default:

$ psql --host=127.0.0.1 --port=5432 --username=APP_USER --dbname=APP_DATABASE
APP_DATABASE=> SELECT version();
APP_DATABASE=> SELECT current_database(), current_user;
APP_DATABASE=> \q

Run the application's read and write smoke tests, inspect the new cluster log, check extension versions, and verify scheduled jobs, connection pools, replication and monitoring. A successful pg_upgradecluster exit only means the migration command completed; it does not prove that every client or extension is ready.

6. Keep or remove the old cluster deliberately

Keep the old cluster until the new one has passed application checks and the retention period required by your recovery plan. If you need to inspect the old data, use the port shown by pg_lsclusters and start it explicitly with pg_ctlcluster as root or the appropriate database owner:

sudo pg_ctlcluster OLD_VERSION CLUSTER_NAME start
pg_lsclusters

Do not start both clusters on the same port. If you decide the upgrade must be abandoned, stop the new cluster, keep the old cluster and restore the connection configuration that pointed clients at the old port. The exact service, pool and application changes are deployment-specific, so record them before the window begins.

Only after the new cluster is accepted and the backup or retention policy allows removal should you delete the old cluster:

sudo pg_dropcluster OLD_VERSION CLUSTER_NAME

This is destructive. It removes the old cluster's data and configuration, so check pg_lsclusters and the version and name twice before running it. There is no useful undo for a dropped cluster; recovery then depends on your backup.

Done means

  • You recorded the old version, cluster name, port, data directory and log.
  • A tested backup and a maintenance or rollback plan exist before the upgrade.
  • You chose dump, upgrade, link or clone deliberately.
  • Any extension hooks and locale changes were reviewed before the run.
  • pg_lsclusters shows the intended new cluster online and the old cluster safely retained or removed.
  • Application connections, extensions, jobs, replication and monitoring were checked against the new server.