This guide upgrades a dedicated Rocky Linux 9.2 server from PostgreSQL 16.x to
17.x in place with pg_upgrade. PostgreSQL 17 is installed alongside PostgreSQL
16, and the old data directory is retained for rollback.
The commands use --copy, not --link. Copy mode requires enough free disk
space for another copy of the cluster, but PostgreSQL 16 remains usable until
PostgreSQL 17 receives new production writes.
The paths below match installations made with the official PostgreSQL Yum repository:
|
Adjust them if your current server uses different paths.
1. Inventory the PostgreSQL 16 cluster
Confirm the running version and data directory:
|
Record the cluster encoding, locale, and checksum setting. The new cluster must be initialized compatibly.
|
Check tablespaces because their data also needs space during a copy-mode upgrade:
|
List extensions in every connectable database:
|
Install a PostgreSQL 17-compatible build of every extension containing native
code before running pg_upgrade. Do not manually create those extensions in the
empty PostgreSQL 17 cluster; pg_upgrade migrates their definitions.
2. Update PostgreSQL 16 to its latest minor release
First update the existing 16.x packages. Plan a short outage for this step.
|
Verify that the server is ready:
|
If pgvector was installed from PGXN rather than an RPM, omit pgvector_16* and
update it using the same installation method originally used.
3. Take backups
Stop here if there is no tested backup. Create a logical backup of all databases and roles:
|
Back up the configuration files:
|
Check disk space for the data directory and every user tablespace:
|
A filesystem or VM snapshot taken while PostgreSQL is stopped provides an additional rollback layer.
4. Install PostgreSQL 17 and extensions
Install PostgreSQL 17 alongside PostgreSQL 16:
|
If pgvector was installed from the PostgreSQL Yum repository, install its PostgreSQL 17 package:
|
Prefer the RPM package when available and do not install pgvector with both RPM
and PGXN. If an extension is available only through PGXN, select the PostgreSQL
17 pg_config explicitly:
|
Confirm that both versions are installed:
|
5. Initialize an empty PostgreSQL 17 cluster
Initialize the new cluster with the encoding and locale recorded earlier. Based
on the original Rocky Linux installation, these are likely UTF8 and
en_US.UTF-8:
|
If pg_controldata reported checksum version 1, remove the newly initialized
empty directory and initialize it with checksums instead:
|
Only remove NEW_DATA at this point, while it is a newly initialized empty
cluster. Do not start PostgreSQL 17 yet.
6. Stop database clients and PostgreSQL 16
Stop applications, scheduled jobs, backup jobs, monitoring, and connection pools. Review remaining sessions:
|
Stop both database services:
|
Both services should report inactive.
7. Run the compatibility check
Create a working directory owned by postgres, then run the PostgreSQL 17
pg_upgrade binary with --check:
|
Do not continue unless the final result is:
|
For example, an error about not loading $libdir/vector means the PostgreSQL 17
pgvector library is missing. Install pgvector_17, then rerun the check.
8. Run the PostgreSQL major upgrade
Run the real upgrade in copy mode:
|
Do not use --no-sync on a production server. Read the complete output and run
any required extension-update or index-rebuild scripts exactly as printed. Keep
the generated old-cluster deletion script, but do not run it yet.
9. Migrate configuration
Do not overwrite PostgreSQL 17's entire postgresql.conf with the PostgreSQL 16
file. Compare the files and manually reapply custom settings that remain valid:
|
Review settings such as listen_addresses, port, memory limits, WAL settings,
logging, SSL, and shared_preload_libraries. Any library named in
shared_preload_libraries must also be installed for PostgreSQL 17.
The client authentication files can normally be copied after review:
|
Review postgresql.auto.conf separately and reapply only valid PostgreSQL 17
settings:
|
Check key configuration values before starting the service:
|
10. Start and verify PostgreSQL 17
Switch the enabled service and start PostgreSQL 17:
|
Verify the server identity, data directory, encoding, and locale:
|
Check that all databases are present:
|
11. Update extensions
First run any extension-update script produced by pg_upgrade. Then list the
installed extension versions:
|
Update pgvector in each database that uses it:
|
Update other extensions only where they are installed:
|
12. Regenerate optimizer statistics
pg_upgrade does not transfer optimizer statistics. Regenerate them in stages
before returning the server to normal traffic:
|
After normal operation resumes, run a complete analyze:
|
13. Validate before deleting PostgreSQL 16
Review the service log:
|
Check for invalid indexes in each important database:
|
Validate database and table counts, important row counts, application login,
reads and writes, scheduled jobs, backups, monitoring, connection pools, and
pgvector searches and indexes. Keep the PostgreSQL 16 packages and
/var/lib/pgsql/16/data for an agreed retention period.
Roll back before production writes
Because the upgrade used --copy, PostgreSQL 16 remains unchanged. Before
PostgreSQL 17 receives production writes, rollback is straightforward:
|
After clients write to PostgreSQL 17, restarting PostgreSQL 16 would discard those new writes. Stop all clients and plan how to export or reconcile the PostgreSQL 17 changes before attempting rollback.
Final cleanup
Only after PostgreSQL 17 has passed validation and fresh backups are working, disable PostgreSQL 16 permanently:
|
After the retention period, remove the old packages. Review the DNF transaction before accepting it so that libraries required by other software are not removed:
|
Finally, delete the old cluster only when you are certain it is no longer needed.
Use the deletion script generated by pg_upgrade, or archive the old data
directory according to your backup and retention policy.