Currently viewing the human version
Switch to AI version

What is pg_upgrade and Why You Should Give a Damn

PostgreSQL Architecture

I've spent more weekends than I care to count sitting in a data center watching pg_dump crawl through 500GB databases. pg_upgrade saved my sanity.

The Traditional Upgrade Nightmare

Before pg_upgrade, upgrading PostgreSQL major versions meant:

  • Dumping your entire database with pg_dump (6 hours for our main DB)
  • Installing the new PostgreSQL version
  • Restoring everything with pg_restore (another 8 hours if you're lucky)
  • Praying nothing broke during the 14-hour maintenance window

I learned this the hard way during a PostgreSQL 9.6 to 11 upgrade that took 16 hours and required rolling back at 3 AM because we hit extension compatibility issues nobody tested.

How pg_upgrade Actually Works

PostgreSQL Architecture

pg_upgrade works at the file system level instead of dumping logical data. It literally moves or links your data files from the old PostgreSQL installation to the new one.

Three modes that matter:

  • Copy mode: Copies all data files (safe but slow, 2x disk space needed)
  • Link mode: Hard links files (fast but scary - if it fails halfway through, you're fucked)
  • Clone mode: File system clones where supported (best of both worlds)

Real-World Performance

Our 500GB production database that used to take 14+ hours with dump/restore? pg_upgrade in copy mode: 45 minutes. Link mode: 8 minutes.

Small databases under 50GB typically upgrade in 10-20 minutes with copy mode. Medium databases (50-500GB) take 30 minutes to 2 hours. Large databases benefit massively from link mode but carry the risk.

Version Support Reality Check

Database Migration Process

pg_upgrade supports PostgreSQL 9.2+ to current versions. You can jump multiple major versions in one go - I've successfully upgraded 9.6 directly to 14 without intermediate steps.

PostgreSQL 18 GA was released September 25, 2025. The new --jobs flag in recent versions lets you parallelize the upgrade, cutting time in half for databases with multiple tablespaces.

Things That Will Bite You

  • Extension hell: Third-party extensions are where upgrades go to die. PostGIS upgrades have ruined more of my weekends than I want to admit.
  • Authentication failures: The upgrade process connects multiple times. Set up peer authentication or you'll be typing passwords for an hour.
  • Disk space: Copy mode needs 2x your database size. I've seen upgrades fail at 90% completion because /var filled up.
  • Replication: Standby servers need special handling. The docs make it sound simple - it's not.

Link mode is fast but unforgiving. If the upgrade fails after it starts linking files, your old cluster is toast. Always test in staging first and have backups. I've had to restore from backups twice when link mode upgrades failed spectacularly.

PostgreSQL Upgrade Methods Reality Check

Feature

pg_upgrade

pg_dump/pg_restore

Logical Replication

Blue/Green

Actual Downtime

15 min

  • 3 hours

4

  • 24+ hours

Near-zero (if it works)

5-15 minutes

Real Performance

Fast but depends on mode

Painfully slow

Gradual, then panic sync

Fast if automated

Disk Space

2x in copy mode

3x+ (temp dump files)

2x running clusters

2x infrastructure

How Hard to Fuck Up

Medium

Low

High (so many gotchas)

Very High

When It Breaks

Extension hell

Rarely

Replication lag nightmares

Infrastructure failures

Rollback Reality

Copy mode only

Easy if you have time

Complex slot management

Flip a switch

Version Limitations

9.2+ only

Any to any

10+ with caveats

Any with effort

Extension Pain

Mostly automated

All manual work

All manual + version drift

All manual

DB Size Sweet Spot

50GB+

Under 50GB

Any with patience

Any with budget

What It Costs

Your weekend

Your sanity

Your sleep

Your infrastructure budget

Actually Running pg_upgrade Without Destroying Everything

PostgreSQL Upgrade Process

After fucking up my first pg_upgrade attempt in 2018, I've learned what actually matters vs. what the documentation glosses over.

Before You Even Think About Upgrading

Step 1: Test in staging or you're an idiot
Seriously. I can't stress this enough. That "simple" PostgreSQL 12 to 13 upgrade? Broke our entire authentication system because we had custom pg_hba.conf settings that weren't compatible.

Step 2: Check your extensions
Run this first:

SELECT name, default_version, installed_version 
FROM pg_available_extensions 
WHERE installed_version IS NOT NULL;

PostGIS, TimescaleDB, and other third-party extensions will ruin your day. I've had upgrades fail because of a single obscure extension that wasn't compatible with the target PostgreSQL version.

Step 3: Disk space reality check
Copy mode needs 2x your database size. Don't fuck around with this - I've seen upgrades fail at 90% completion and corrupt data because someone thought "close enough" on disk space was acceptable.

The Actual pg_upgrade Command That Works

Stop overthinking it. Here's what actually works:

## Always run the check first
pg_upgrade \
  --old-datadir /var/lib/postgresql/14/main \
  --new-datadir /var/lib/postgresql/17/main \
  --old-bindir /usr/lib/postgresql/14/bin \
  --new-bindir /usr/lib/postgresql/17/bin \
  --check

## If check passes, run the real upgrade
pg_upgrade \
  --old-datadir /var/lib/postgresql/14/main \
  --new-datadir /var/lib/postgresql/17/main \
  --old-bindir /usr/lib/postgresql/14/bin \
  --new-bindir /usr/lib/postgresql/17/bin \
  --jobs 4

Critical flags that matter:

  • --check: Tests compatibility without touching anything. The docs say it's optional - it's not.
  • --jobs 4: Parallel processing. Use your CPU core count or number of tablespaces, whichever is higher.
  • --link: Fast but dangerous. Only use if you're confident and have backups.

Performance Tips From Hard Experience

For databases under 100GB: Copy mode, 15-30 minutes typical
For databases 100-500GB: Copy mode, 30 minutes to 2 hours depending on disk speed
For databases 500GB+: Link mode or plan for a long weekend

The --jobs flag is magic for large databases. Our 800GB database went from 3 hours to 45 minutes with --jobs 8.

What Actually Breaks During Upgrades

PostgreSQL Terminal Commands

Authentication problems: pg_upgrade connects to both clusters multiple times. Either set up peer authentication in pg_hba.conf or create a .pgpass file:

localhost:5433:*:postgres:yourpassword
localhost:5432:*:postgres:yourpassword

Extension upgrade failures: The worst offenders:

  • PostGIS (especially versions 2.x to 3.x)
  • TimescaleDB with version compatibility issues
  • Custom C extensions that aren't recompiled

Out of disk space: Happens at the worst possible time. Monitor with df -h during the upgrade.

After the Upgrade Completes

Don't celebrate yet. Run these immediately:

## Update statistics (this is not optional)
vacuumdb --all --analyze-only

## Check that everything actually works
psql -c \"SELECT version();\"

The generated scripts in your data directory aren't suggestions - run them. I've seen subtle performance issues because people skipped the post-upgrade maintenance.

When Everything Goes to Shit

If pg_upgrade fails:

  1. Don't panic - your old cluster is intact (if you used copy mode)
  2. Read the actual error message - don't just restart
  3. Check logs in the pg_upgrade output directory
  4. Most common fixes: extension issues, authentication problems, or disk space

I keep a rollback script ready:

#!/bin/bash
## Stop new cluster
systemctl stop postgresql
## Restore old cluster configuration  
systemctl start postgresql@14-main

Link mode failures are scarier because you might lose both clusters. This is why I only use link mode after successful copy mode tests in staging.

Questions People Actually Ask (And Honest Answers)

Q

How fucked am I if pg_upgrade fails halfway through?

A

If you used copy mode: you're fine, your old cluster is intact.

Restart it and figure out what broke.If you used link mode: you're potentially fucked. Link mode starts modifying files immediately, so if it fails partway through you might lose both clusters. This is why you test in staging first and have backups.The --check flag exists for a reason

  • use it. I've seen it catch extension conflicts, authentication issues, and disk space problems before they destroy anything.
Q

What's this copy vs link vs clone mode bullshit?

A

Copy mode:

Makes complete copies of your data files. Safe but slow, needs 2x disk space. If it fails, your original database is fine.Link mode: Creates hard links to your data files instead of copying.

Fast as hell (minutes instead of hours) but scary

  • if anything goes wrong, both your old and new clusters share the same files.Clone mode: Uses filesystem cloning where supported (ZFS, APFS, etc.). Fast like link mode but safer because it creates actual copies at the filesystem level.I use copy mode for production upgrades unless downtime requirements force me to use link mode after extensive staging tests.
Q

How long does this actually take?

A

Real timelines from production experience:

  • Small databases (under 50GB): 15-30 minutes in copy mode, 5-10 minutes in link mode
  • Medium databases (50-500GB): 30 minutes to 2 hours in copy mode, 10-20 minutes in link mode
  • Large databases (500GB+): 2-6 hours in copy mode, 20-60 minutes in link modeThe --jobs flag is magic for large databases. Our 800GB database went from 4 hours to 45 minutes with --jobs 8.
Q

Why does pg_upgrade keep asking for passwords?

A

Because it connects to both clusters multiple times during the upgrade process.

Fix this by either: 1.

Setting up peer authentication in pg_hba.conf:local all postgres peer2.

Creating a .pgpass file:localhost:5432:*:postgres:yourpasswordlocalhost:5433:*:postgres:yourpasswordOtherwise you'll be typing passwords for an hour.

Q

What's the deal with extensions breaking everything?

A

Extensions are where pg_upgrade goes to die.

The worst offenders:

  • PostGIS:

Version compatibility is a nightmare, especially 2.x to 3.x upgrades

  • TimescaleDB: Often requires specific upgrade procedures
  • Custom C extensions:

Need to be recompiled for new PostgreSQL versionsRun this before upgrading to see what you're dealing with:```sql

SELECT name, default_version, installed_version FROM pg_available_extensions WHERE installed_version IS NOT NULL;```When in doubt, remove problematic extensions before upgrading and reinstall compatible versions after.

Q

Can I upgrade from PostgreSQL 9.6 to 17 directly?

A

Yes, pg_upgrade supports multi-version jumps. I've done 9.6 → 14 upgrades successfully. But read the release notes for breaking changes across that many versions

  • authentication, configuration syntax, and deprecated features can bite you.
Q

What happens to my replication setup?

A

Replication makes everything more complicated.

You need to:

  1. Upgrade the primary first
  2. Use rsync to sync the upgraded data to standbys
  3. Recreate replication slots and streaming connections

PostgreSQL 17+ has better replication slot migration, but it's still not automatic. Plan for extra complexity and testing.

Q

How much disk space do I actually need?

A

Copy mode: 2x your database size minimum.

Don't fuck around with this

  • I've seen upgrades fail at 90% because someone thought "close enough" was acceptable.Link mode: Almost no extra space since it uses hard linksClone mode: Minimal extra space, depends on your filesystemAlways check with df -h before starting and monitor during the upgrade.
Q

Should I use this in production?

A

PostgreSQL Logo AlternativeIf your database is over 50GB and you can't afford 12+ hours of downtime for dump/restore, then yes.

But:

  • Test in staging first (non-negotiable)
  • Use copy mode unless you're desperate
  • Have proper backups
  • Have a rollback plan
  • Schedule a maintenance window

I've used pg_upgrade for dozens of production upgrades. When properly tested, it's reliable. When not tested, it's a career-limiting move.

Related Tools & Recommendations

tool
Similar content

pg_dumpall - Back up entire PostgreSQL clusters

The nuclear option for PostgreSQL backups - gets everything or nothing

pg_dumpall
/tool/pg-dumpall/overview
100%
tool
Similar content

PostgreSQL Logical Replication - When Streaming Replication Isn't Enough

Unlock PostgreSQL Logical Replication. Discover its purpose, how it differs from streaming replication, and a practical guide to setting it up, including tips f

PostgreSQL
/tool/postgresql/logical-replication
76%
howto
Similar content

PostgreSQL 16 to 17 Zero-Downtime Upgrade Using Logical Replication

I've Done This Twice. The First Time Was a Disaster. Here's How to Do It Right.

PostgreSQL
/howto/zero-downtime-database-migration-postgresql-mysql/postgresql-logical-replication-upgrade
74%
howto
Similar content

How I Migrated Our MySQL Database to PostgreSQL (And Didn't Quit My Job)

Real migration guide from someone who's done this shit 5 times

MySQL
/howto/migrate-legacy-database-mysql-postgresql-2025/beginner-migration-guide
63%
compare
Similar content

PostgreSQL vs MySQL vs MariaDB - Performance Analysis 2025

Which Database Will Actually Survive Your Production Load?

PostgreSQL
/compare/postgresql/mysql/mariadb/performance-analysis-2025
43%
howto
Similar content

How to Migrate PostgreSQL 15 to 16 Without Destroying Your Weekend

Learn how to safely migrate PostgreSQL 15 to 16 in a production environment. This guide covers migration methods, potential pitfalls, and troubleshooting steps

PostgreSQL
/howto/migrate-postgresql-15-to-16-production/migrate-postgresql-15-to-16-production
36%
troubleshoot
Similar content

PostgreSQL Breaks in Creative Ways - Here's How to Fix the Disasters

The most common production-killing errors and how to fix them without losing your sanity

PostgreSQL
/troubleshoot/postgresql-performance/common-errors-solutions
33%
tool
Recommended

PostgreSQL Logical Replication Performance - How to Not Let WAL Bloat Kill Your Database

competes with PostgreSQL

PostgreSQL
/tool/postgresql-logical-replication/performance-optimization
32%
tool
Recommended

AWS RDS - Amazon's Managed Database Service

alternative to Amazon RDS

Amazon RDS
/tool/aws-rds/overview
32%
tool
Recommended

AWS RDS Blue/Green Deployments - Zero-Downtime Database Updates

alternative to AWS RDS Blue/Green Deployments

AWS RDS Blue/Green Deployments
/tool/aws-rds-blue-green-deployments/overview
32%
tool
Recommended

Google Cloud SQL - Database Hosting That Doesn't Require a DBA

MySQL, PostgreSQL, and SQL Server hosting where Google handles the maintenance bullshit

Google Cloud SQL
/tool/google-cloud-sql/overview
32%
howto
Similar content

Zero Downtime Database Migration: Don't Break Production

How to migrate your database without taking down the site (and pissing off customers)

Liquibase
/howto/zero-downtime-database-migration/production-migration-guide
30%
alternatives
Similar content

MySQL Alternatives - Time to Jump Ship?

MySQL silently corrupted our production data for the third time this year. That's when I started seriously looking at alternatives.

MySQL
/alternatives/mysql/migration-ready-alternatives
30%
howto
Similar content

Set Up PostgreSQL Streaming Replication Without Losing Your Sanity

Master PostgreSQL streaming replication for production. This guide covers prerequisites, primary/standby setup, data synchronization, and FAQs to achieve high a

PostgreSQL
/howto/setup-production-postgresql-replication/production-streaming-replication-setup
30%
tool
Similar content

PostgreSQL Performance Optimization - Stop Your Database From Shitting Itself Under Load

Optimize PostgreSQL performance with expert tips on memory configuration, query tuning, index design, and production monitoring. Prevent outages and speed up yo

PostgreSQL
/tool/postgresql/performance-optimization
30%
tool
Similar content

PostgreSQL - The Database You Use When MySQL Isn't Enough

Explore PostgreSQL's advantages over other databases, dive into real-world production horror stories, solutions for common issues, and expert debugging tips.

PostgreSQL
/tool/postgresql/overview
29%
tool
Similar content

Bucardo - Multi-Master PostgreSQL Replication That Actually Works

The only PostgreSQL multi-master that actually works (despite the trigger hell). Been doing real bidirectional sync since 2007 when everyone else was still pret

Bucardo
/tool/bucardo/overview
26%
tool
Similar content

CockroachDB - PostgreSQL That Scales Horizontally

Distributed SQL database that's more complex than single-node databases, but works when you need global distribution

CockroachDB
/tool/cockroachdb/overview
26%
pricing
Similar content

Database Hosting Costs: PostgreSQL vs MySQL vs MongoDB

Compare the true hosting costs of PostgreSQL, MySQL, and MongoDB. Get a detailed breakdown to find the most cost-effective database solution for your projects.

PostgreSQL
/pricing/postgresql-mysql-mongodb-database-hosting-costs/hosting-cost-breakdown
26%
tool
Similar content

RHACS Troubleshooting Guide: Fix the Stuff That Breaks

When your security platform decides to become the security problem

Red Hat Advanced Cluster Security for Kubernetes
/tool/red-hat-advanced-cluster-security/troubleshooting-guide
26%

Recommendations combine user behavior, content similarity, research intelligence, and SEO optimization