Skip to main content

PostgreSQL Version Upgrades

Introduction

Upgrading your PostgreSQL database to a newer version is a critical maintenance task that every database administrator will eventually face. While newer PostgreSQL versions bring performance improvements, security patches, and exciting features, the upgrade process requires careful planning and execution to avoid data loss or extended downtime.

This guide will walk you through the PostgreSQL version upgrade process, covering different upgrade methods, best practices, and common pitfalls to avoid. Whether you're managing a small development database or a mission-critical production system, you'll learn how to approach upgrades methodically and safely.

Why Upgrade PostgreSQL?

Before diving into the upgrade process, let's understand why upgrading PostgreSQL is important:

  • Security patches: Newer versions fix security vulnerabilities
  • Performance improvements: Each version typically brings performance optimizations
  • New features: Access to new SQL capabilities, improved indexing options, etc.
  • Bug fixes: Resolution of known issues from previous versions
  • Community support: Older versions eventually reach end-of-life (EOL) status

Understanding PostgreSQL Versioning

PostgreSQL follows a versioning scheme that's important to understand when planning upgrades:

  • Major version upgrades (e.g., 13 to 14): Require dump/restore or pg_upgrade
  • Minor version upgrades (e.g., 14.1 to 14.2): Can be done with a simple installation of binaries and restart

Version Upgrade Methods

PostgreSQL offers several methods for performing major version upgrades:

1. Dump and Restore

The most reliable but potentially slowest method involves exporting data from the old version and importing it into a new installation.

Steps:

  1. Back up your current database:
bash
pg_dumpall -U postgres > full_backup.sql
  1. Install the new PostgreSQL version

  2. Initialize a new data directory:

bash
# For PostgreSQL 14 example
/usr/pgsql-14/bin/initdb -D /var/lib/pgsql/14/data
  1. Configure the new PostgreSQL instance

  2. Start the new PostgreSQL server

  3. Restore the data:

bash
psql -U postgres -f full_backup.sql

Pros and Cons:

✅ Most reliable upgrade method that handles all schema changes cleanly
✅ Works across any PostgreSQL version jump
✅ Provides opportunity to restructure or clean data
❌ Longest downtime of all methods
❌ Can be very slow for large databases

2. Using pg_upgrade

The pg_upgrade utility, introduced in PostgreSQL 9.0, provides a faster alternative that can significantly reduce downtime.

Steps:

  1. Install the new PostgreSQL version alongside the existing one

  2. Stop the current PostgreSQL server:

bash
systemctl stop postgresql-13
  1. Run pg_upgrade:
bash
# Example for upgrading from 13 to 14
/usr/pgsql-14/bin/pg_upgrade \
--old-datadir=/var/lib/pgsql/13/data \
--new-datadir=/var/lib/pgsql/14/data \
--old-bindir=/usr/pgsql-13/bin \
--new-bindir=/usr/pgsql-14/bin \
--old-options="-c config_file=/var/lib/pgsql/13/data/postgresql.conf" \
--new-options="-c config_file=/var/lib/pgsql/14/data/postgresql.conf"
  1. Start the new PostgreSQL server:
bash
systemctl start postgresql-14
  1. Run the suggested analyze script:
bash
./analyze_new_cluster.sh

Pros and Cons:

✅ Much faster than dump and restore
✅ Significantly reduced downtime
✅ Works across multiple major versions
❌ May not work with certain extensions or custom setups
❌ Requires additional disk space during upgrade

3. Logical Replication Upgrade

For minimal downtime in production environments, logical replication offers the most sophisticated solution.

Steps:

  1. Set up logical replication on the current PostgreSQL server:
sql
-- On source (old) PostgreSQL
ALTER SYSTEM SET wal_level = logical;
-- Restart the server for this to take effect
  1. Create a publication on the source server:
sql
CREATE PUBLICATION full_publication FOR ALL TABLES;
  1. Install and configure the new PostgreSQL version on a separate server

  2. Create a subscription on the target server:

sql
-- On target (new) PostgreSQL
CREATE SUBSCRIPTION full_subscription
CONNECTION 'host=source_host port=5432 dbname=mydb user=replication_user password=secretpassword'
PUBLICATION full_publication;
  1. Monitor replication until it's in sync

  2. Perform the switchover:

    • Stop writes to the old server
    • Verify synchronization is complete
    • Redirect clients to the new server

Pros and Cons:

✅ Minimal downtime (seconds to minutes)
✅ Allows testing the new version with real data before switching
✅ Can upgrade across multiple major versions
❌ Most complex setup of all methods
❌ Requires additional hardware during migration
❌ Some limitations with certain data types or operations

Practical Upgrade Example: PostgreSQL 13 to 14

Let's walk through a complete example of upgrading from PostgreSQL 13 to 14 using pg_upgrade on a Linux system.

Preparation Phase

  1. Check for compatibility issues:
bash
# Install new version without initializing
sudo dnf install -y postgresql14-server

# Validate compatibility of extensions
psql -c "SELECT name, default_version FROM pg_available_extensions ORDER BY name;"
  1. Back up your database (always!):
bash
pg_dumpall -U postgres > pg13_full_backup.sql
  1. Update your applications to work with PostgreSQL 14 if needed

Execution Phase

  1. Stop the current PostgreSQL 13 server:
bash
sudo systemctl stop postgresql-13
  1. Initialize the new PostgreSQL 14 data directory:
bash
sudo /usr/pgsql-14/bin/postgresql-14-setup initdb
  1. Run pg_upgrade with check mode first:
bash
sudo -u postgres /usr/pgsql-14/bin/pg_upgrade \
--old-datadir=/var/lib/pgsql/13/data \
--new-datadir=/var/lib/pgsql/14/data \
--old-bindir=/usr/pgsql-13/bin \
--new-bindir=/usr/pgsql-14/bin \
--check
  1. If check passes, run the actual upgrade:
bash
sudo -u postgres /usr/pgsql-14/bin/pg_upgrade \
--old-datadir=/var/lib/pgsql/13/data \
--new-datadir=/var/lib/pgsql/14/data \
--old-bindir=/usr/pgsql-13/bin \
--new-bindir=/usr/pgsql-14/bin
  1. Start the new PostgreSQL 14 server:
bash
sudo systemctl start postgresql-14
sudo systemctl enable postgresql-14
  1. Run the post-upgrade analysis:
bash
sudo -u postgres ./analyze_new_cluster.sh
  1. Verify the upgrade:
bash
psql -U postgres -c "SELECT version();"

Cleanup Phase

Once you've confirmed everything works correctly:

bash
sudo -u postgres ./delete_old_cluster.sh

Common Challenges and Solutions

Dealing with Incompatible Extensions

Some extensions may not be immediately compatible with the new PostgreSQL version.

Solution: Check extension compatibility before upgrading, and:

  • Update extensions to compatible versions
  • Look for alternative extensions if needed
  • Consider contacting extension maintainers for updates

Handling Configuration Changes

New PostgreSQL versions often introduce new configuration parameters or deprecate old ones.

Solution:

  • Review release notes for configuration changes
  • Use postgresql.conf.sample from the new version as reference
  • Test configuration with development databases first

Example configuration migration strategy:

bash
# Extract current configuration
grep -v "#" /var/lib/pgsql/13/data/postgresql.conf | grep -v "^$" > pg13_active_config.txt

# Compare with new sample configuration
diff pg13_active_config.txt /usr/pgsql-14/share/postgresql.conf.sample

Managing Large Databases

Large databases can make the upgrade process challenging and time-consuming.

Solution:

  • For pg_upgrade, use the --link option to avoid copying data files (when possible)
  • Consider logical replication for minimal downtime
  • Schedule upgrades during maintenance windows
  • Parallelize dump/restore operations for multiple databases

Best Practices for PostgreSQL Upgrades

  1. Always create full backups before attempting an upgrade

  2. Test the upgrade process in a development/staging environment first

  3. Read the release notes carefully for each version you're upgrading through

  4. Plan for rollback in case something goes wrong

  5. Schedule appropriate downtime and notify users

  6. Check applications and connection strings for compatibility

  7. Upgrade one major version at a time when possible (e.g., 12 → 13 → 14)

  8. Perform upgrades during low-traffic periods

  9. Validate post-upgrade with tests and monitoring

  10. Keep previous data directory until you confirm success

Monitoring the Upgrade Process

Monitor these key metrics during and after upgrades:

  1. Database performance (query times, transaction rates)
  2. Resource utilization (CPU, memory, disk I/O)
  3. Error rates in logs
  4. Application connectivity
  5. Replication lag (if using logical replication)

Example commands for post-upgrade checks:

sql
-- Check for invalid indexes
SELECT * FROM pg_class c, pg_index i
WHERE c.oid = i.indexrelid AND i.indisvalid = false;

-- Check for invalidated caches
SELECT datname, datfrozenxid, age(datfrozenxid)
FROM pg_database ORDER BY age(datfrozenxid) DESC;

Automated Upgrades

For teams managing multiple PostgreSQL instances, automation becomes critical.

Example Ansible playbook snippet for PostgreSQL upgrade:

yaml
- name: PostgreSQL Upgrade
hosts: pg_servers
become: yes
vars:
old_version: 13
new_version: 14

tasks:
- name: Stop PostgreSQL old version
systemd:
name: "postgresql-{{ old_version }}"
state: stopped

- name: Run pg_upgrade
command: >
/usr/pgsql-{{ new_version }}/bin/pg_upgrade
--old-bindir=/usr/pgsql-{{ old_version }}/bin
--new-bindir=/usr/pgsql-{{ new_version }}/bin
--old-datadir=/var/lib/pgsql/{{ old_version }}/data
--new-datadir=/var/lib/pgsql/{{ new_version }}/data
become_user: postgres

- name: Start PostgreSQL new version
systemd:
name: "postgresql-{{ new_version }}"
state: started
enabled: yes

Summary

Upgrading PostgreSQL requires careful planning and execution but brings significant benefits in terms of performance, security, and features. By understanding the available upgrade methods and following best practices, you can minimize risk and downtime during the upgrade process.

Remember these key points:

  • Choose the right upgrade method based on your database size and downtime tolerance
  • Always back up your data before upgrading
  • Test the upgrade process in a non-production environment
  • Read the release notes for each version you're upgrading through
  • Monitor system performance before and after the upgrade

Further Resources

Practice Exercises

  1. Set up a development PostgreSQL 13 instance and practice upgrading it to version 14
  2. Create a checklist for PostgreSQL upgrades specific to your environment
  3. Compare the performance of a sample database before and after upgrade
  4. Practice using logical replication to upgrade a database with minimal downtime
  5. Write a script to automate the upgrade process for your environment


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)