PostgreSQL major upgrade with pg_upgrade or logical replication

Choosing a PostgreSQL major upgrade method comes down to downtime budget, rollback needs and the work your team can test in advance. This page explains how pg_upgrade and logical replication compare and what each one requires.

On this page

How to choose a PostgreSQL major upgrade method by downtime budget

The method is chosen by how much downtime the business accepts and how much rollback time it needs. A short window favors a logical replication cutover, which the PostgreSQL documentation describes as working between major versions with only several seconds of downtime. A longer window lets a team use an offline method with a simpler run path. PostgreSQL 14 is supported until November 12, 2026, so a cluster on that version has a fixed deadline, and the downtime budget should be set before the method is picked. Ask the business two questions: how many minutes of write unavailability are acceptable at cutover, and how long the old cluster must stay intact so it can be restarted if the new one misbehaves.

The supported major upgrade paths are pg_dumpall with restore, pg_upgrade, and logical replication. A dump and restore rebuilds the cluster from logical copies, so its duration grows with data volume and index rebuilds, which makes it a difficult fit for a tight window unless the database is small. pg_upgrade converts the on-disk data for the new major version. Its link mode avoids copying data files, which shortens the data step, but the old cluster's files are shared with the new one, so the rollback options change. Logical replication copies changes from the old server to a server running the target major version, so cutover becomes a switch of client connections. PostgreSQL 18 adds planner statistics retention across major upgrades, parallel jobs and a --swap option, so confirm which of these your chosen path uses.

Each major version receives support for five years after its initial release, and a new major version arrives about once a year. The supported versions are 18, first released September 25, 2025 and supported until November 14, 2030, 17 until November 8, 2029, 16 until November 9, 2028, 15 until November 11, 2027, and 14 until November 12, 2026. Versions 13 and earlier are already unsupported. A move from 14 to 15 or 16 would bring another major upgrade closer, so the target should be the newest version the team can test and execute within its window. Confirm extension and client driver compatibility for that target before setting the cutover date.

Minor releases are a different operation. Minor PostgreSQL releases never change the internal storage format, so updating means replacing executables and restarting the server, which is why minor updates can be scheduled as routine maintenance. Major upgrades change the stored format or require a logical copy, so swapping binaries alone does not move a cluster to a new major version. Plan the window around that difference: a minor update is a restart, while a major path needs one of the three methods above plus a rollback plan. Rehearse the chosen method on a copy of production, record the measured cutover time, and confirm rollback steps in the upgrading documentation for your exact source and target versions before approving the downtime budget.

What changes across the PostgreSQL releases you will upgrade through

This table lists the PostgreSQL 18 changes and pg_upgrade behavior that affect an upgrade, with the impact on your cluster and the action to take before cutover. Read each row against your source version, because the official release notes for every version between your source and target must be checked before the plan is final. The main takeaway is that the authentication and generated column rows are the most likely to break applications, so test them first.

ChangeImpact on your upgradeAction needed
Asynchronous I/O (PostgreSQL 18)Changes how the server issues disk reads, so throughput and latency can shift after the upgrade.Benchmark key queries and batch jobs on the target in rehearsal and compare them with the source baseline.
MD5 password authentication deprecated (PostgreSQL 18)Deprecated in favor of SCRAM, so roles and clients still using MD5 need attention before or during the move.List roles with MD5-hashed passwords, plan resets to SCRAM and confirm every client driver supports SCRAM.
uuidv7() added (PostgreSQL 18)Adds a new function. The upgrade does not change existing UUID values or application code.Decide whether new keys will use uuidv7(), and check that application code and indexes match that choice.
Virtual generated columns by default (PostgreSQL 18)Generated columns without an explicit storage type are virtual, so values compute on read instead of being stored.Find generated columns in your DDL, decide which need STORED, and test queries that depend on them.
Planner statistics retained (pg_upgrade, PostgreSQL 18)Statistics carry across the major upgrade, which affects whether a full ANALYZE is needed before users reconnect.Confirm in rehearsal whether plans match the source, and set the post-cutover ANALYZE step from that result.
Parallel jobs and --swap (pg_upgrade, PostgreSQL 18)Parallel jobs can shorten the conversion step, and --swap changes how the old data directory is handled.Measure run time in rehearsal and confirm in the pg_upgrade documentation what --swap does before using it in a rollback plan.
Client authentication methodsPassword, GSSAPI, SSPI, LDAP, RADIUS, certificate, PAM and OAuth are documented methods, and pg_hba.conf rules often change with the upgrade.Diff pg_hba.conf between source and target, then test each client path, including OAuth on PostgreSQL 18.
Intermediate versions (15, 16 and 17)Changes in each intermediate version can affect applications and are not covered by the rows above.Read the official release notes for every intermediate version and record each change that touches your workloads.

How pg_upgrade copy, link, clone and swap modes differ

Copy is the default mode. pg_upgrade reads the old data directory and writes a complete new one, so both clusters hold full copies of the data while the upgrade runs. The old cluster is left untouched, which makes it the simplest rollback point: if the new cluster misbehaves, you can restart the old binaries against the old data directory. Downtime covers the period from stopping the old server to starting the new one, and it grows with data size and the number of schema objects that must be migrated. Disk space is usually the main planning constraint, because you need room for a second full copy.

  • Old directory: kept intact and startable after the upgrade, provided the new cluster has not accepted writes
  • New directory: a full copy written by the new binaries
  • Downtime: scales with data size and catalog objects, so measure it on a rehearsal copy
  • Rollback: restart the old binaries against the untouched old directory
  • Disk: plan for a second full copy of the data directory

Confirm the rollback window and the post-upgrade statistics step in the upgrade documentation for your target version before you write the runbook.

When a logical replication cutover fits a seconds-long downtime budget

Choose a logical replication cutover when your downtime budget is measured in seconds and you can accept extra operational work during the migration window. The PostgreSQL upgrading documentation states that logical replication works between different major versions, which is why it can allow a major upgrade with only several seconds of downtime. That claim is the reason this method exists, but it is not a guarantee for your workload. The actual outage depends on how quickly you can pause writes, drain the final changes, and repoint application connections, so measure those steps in a rehearsal before you commit to a window.

The method has a few moving parts. You create a publication on the old primary that lists the tables to replicate. On the new server running the target major version, you create a subscription that connects to that publication. When the subscription starts, PostgreSQL performs an initial data synchronization, copying the table contents as they stand. After that copy, the subscription applies the changes that accumulated on the old primary, which is the catch-up phase. The cutover itself is a planned switch in which you stop or reduce writes, confirm the subscriber has applied everything, and change application connection strings or a pooler such as PgBouncer to point at the new server.

The operational work starts before cutover and continues after it. Monitor replication lag on the publisher and subscriber throughout the catch-up phase, because a lag that does not shrink means the cutover window will not hold. Logical replication does not carry every kind of object. Sequence values are not replicated automatically, so you need a step that sets sequences on the new server to the correct values at cutover. Schema changes, such as new columns, DDL, and changes to objects outside the published tables, also require manual coordination. Plan a freeze on schema changes for the migration period and confirm which object types your chosen setup replicates, including large objects, triggers, and foreign keys.

Verify all of these constraints against the replication documentation for both the source and target versions before you finalize the plan. The limits on replicated object types, the behavior of sequences, and the options for handling conflicts or initial sync have changed across releases, so read the documentation for the exact versions you will run rather than relying on a general summary. Ask your team or a partner to show, in a rehearsal, how each limit applies to your schema and extensions.

Compare this option against the rollback path it leaves. Because the old cluster keeps running and continues to receive changes until cutover, you can often reverse direction by setting up replication back to the old version, but that reverse path needs its own setup and testing. Decide before the window opens how long you will keep the old primary available, who makes the rollback call, and what data loss you will accept if writes land on the new server before a reversal.

What to back up and inventory before the upgrade starts

Four items decide whether the upgrade can be rolled back and whether applications reconnect cleanly at cutover. Each card names one item to back up, inventory, rehearse or review before you choose a method. Treat them as gates: the upgrade should not be scheduled until the restore has been tested and the rehearsal has run end to end.

Verified backup and recovery path

Take a base backup and archive the WAL files so you can restore to a chosen point in time if the upgrade fails. If you use incremental backups, confirm that pg_combinebackup can reconstruct them at restore time. A backup that has never been restored is not yet a backup you can rely on. Restore it to a separate host, run the application checks against it, and record how long the restore took. The rollback plan should rest on that tested result.

Inventory of extensions, functions and access rules

Record every extension, custom function and trigger in each database, with its installed version and whether it has a build for the target major version. Export pg_hba.conf from each server and list the authentication method for every rule. Identify roles that still use MD5 password hashes, since PostgreSQL 18 deprecates MD5 in favor of SCRAM, and plan that change with the application owners. Keep the inventory with the change record.

Test environment sized to production

Build a test environment from a copy of production data, or a subset agreed with the data owners, on hardware and settings close to production. Size storage and memory from your production inventory so the timings you measure mean something. Run representative application queries and scheduled jobs against the upgraded copy, not just the upgrade commands. Time each step and keep the results, because they set the cutover window you can commit to.

Connection pooling review

Review how applications connect through PgBouncer or any other pooler, including pool mode, client and server connection limits, and retry behavior. Confirm which endpoint points to the old cluster and how it changes at cutover. Test whether applications reconnect automatically after a restart or a logical replication switch. Session-level features and prepared statements can break under some pool modes, so test them too. Record who changes the endpoint and the step that reverses it.

How a PostgreSQL major upgrade runs step by step

The sequence moves a production cluster to a new major version in a controlled order, with a named rollback point at each step. It ends with a validated new cluster, a tested cutover and an old cluster kept intact until the rollback window closes.

  1. Inventory versions, extensions and compatibility

    The DBA or platform engineer lists the source major and minor versions, installed extensions, custom data types, server parameters, authentication settings and every application that connects, including driver versions. They run the compatibility checks in the PostgreSQL upgrade documentation and review the target version's release notes for changes to planner statistics, authentication and defaults. Done when every extension and driver has a confirmed target version and every finding has a named owner. Rollback point: nothing has changed yet, so the production cluster is untouched and fully authoritative.

  2. Rehearse the upgrade on a copy

    The team restores a recent base backup onto separate hardware with the same extensions and configuration, then runs the chosen method end to end against that copy. They replay the application test suite and a sample of real queries, and record every command, error and manual fix in a runbook. Done when a clean run has been repeated from a fresh copy and someone other than the runbook's author can follow it. Set the downtime and rollback windows from the timings measured here, not from documentation estimates. Rollback point: production is still on the old version, and the rehearsal copy can be discarded at any time.

  3. Freeze schema changes and scheduled writes

    The change owner places a freeze on DDL, extension changes, role changes and configuration edits for the affected databases, starting at rehearsal sign-off and ending when the rollback window closes. Schedulers, migration tools and ETL jobs that create or alter schema objects are paused or confirmed idle. The owner confirms the freeze in writing, and the monitoring team checks the database logs for unplanned DDL during the freeze. Done when the freeze is recorded and no unplanned schema changes appear. Rollback point: the freeze does not alter the old cluster, so lifting it returns the environment to its prior state.

  4. Take and restore-test the final backup

    The DBA takes a fresh base backup of the old cluster and confirms that the WAL archive is continuous through the backup time. They restore it to a scratch host, confirm that the instance starts, and compare a sample of tables against the source. The backup is stored away from the upgrade hosts so that a failed upgrade cannot damage it. Done when the restore test passes and the backup identifier is written into the change record. Rollback point: this backup is the restore path if the new cluster must be discarded after switchover, because the old cluster is no longer the only current copy once traffic moves.

  5. Run pg_upgrade or set up logical replication

    For pg_upgrade, stop the old cluster, run the check mode first, then run the upgrade in the mode the target version and filesystem support (copy, link, clone or swap). For logical replication, install the target version beside the source, copy the schema, create publications on the old cluster and subscriptions on the new one, then wait for the initial table sync and watch replication lag until it stays low. Logical replication does not carry DDL, so schema changes must be held by the freeze, and sequence values are set during cutover. Done when pg_upgrade reports success, or every table is in a ready state with lag under control. Rollback point: pg_upgrade copy mode leaves the old cluster intact, while link and swap modes change files the old cluster uses, so rollback then depends on the final backup. With logical replication, the old primary stays authoritative until cutover.

  6. Validate row counts, statistics and queries

    The team compares row counts and checksums for a defined set of large and business-critical tables between the old and new clusters, using queries run at a quiet point. They confirm that planner statistics are present, run ANALYZE where the method did not carry them over, and compare plans for the slowest statements in the application log. The application test suite and smoke checks then run against the new cluster. Done when every compared table matches, the top query set meets the thresholds agreed in rehearsal, and the application owner signs off. Rollback point: the new cluster is still a candidate, so the old cluster remains authoritative and production traffic has not moved.

  7. Switch connections to the new cluster

    The team stops writes to the old cluster, waits for logical replication to reach zero lag where it was used, and sets sequences on the new cluster. They then point the connection pooler and the database endpoints at the new cluster and re-enable writers. Done when the new cluster accepts writes, connections arrive on the new server, and errors and latency stay within the rehearsal thresholds, with the cutover time recorded in the change record. Rollback point: after the switch the old primary is no longer current. Returning to it needs reverse replication from the new cluster or a restore from the final backup, so the team must choose which path applies before cutover begins.

  8. Hold the old cluster through the rollback window

    The team keeps the old cluster intact, in the state the runbook defines, and retains its backups and WAL archive for the window set during rehearsal. They watch the new cluster through its first full business cycles, including batch jobs and reporting, and log any issue against the agreed rollback criteria. When the criteria are met, the change owner closes the window in writing, and the team then updates backup policy and monitoring for the new version. Done when the sign-off is recorded and the old data directory is archived or removed under the change process. Rollback point: until the window closes, the old cluster and the final backup remain the fallback, and the runbook sets when that fallback expires.

How to rehearse the cutover and decide when to roll back

Write down the rollback path for your method before the first rehearsal, because the options differ sharply. With pg_upgrade in copy mode, the old data directory is normally left in place, so a fallback means starting the old cluster from its own binaries and data directory. That works only until the new cluster accepts writes you need to keep. In link mode, the new cluster's files are hard links to the old cluster's files, so the old cluster cannot simply be restarted once the new one has run. Treat that as a one-way step unless you have a verified restore. Confirm the exact behavior for your source and target versions in the upgrade documentation, and record the answer in the runbook so no one has to reconstruct it during an incident.

With logical replication, the old primary stays writable until the switch, which gives you a clean fallback up to the cutover point. The gap opens after the switch. Writes accepted by the new primary exist only there, so reverting means one of two things: a reverse logical replication stream from the new server back to the old one, configured before the switch and tested in the rehearsal, or a restore from backup followed by replay of the lost window. Reverse replication has its own prerequisites, including how sequence values are carried back and how conflicts are handled, so confirm them against the replication documentation for your versions. Decide in advance how long the reverse path stays open and who has authority to close it.

Set go and no-go criteria as measurable checks that the application owner, the database owner and the person who can call a rollback all agree to. Useful gates include a clean preflight run (pg_upgrade --check or the equivalent for your method), confirmed extension versions on the target, matching row counts or checksums for agreed critical tables, application test suites passing against the new cluster, zero replication lag on the logical stream before the switch, and a measured cutover time that fits your downtime budget. Attach a no-go trigger to each gate. For example, a failed reconciliation on a ledger table should stop the cutover automatically, so nobody debates it under pressure.

Run rehearsals until the procedure is routine. The first rehearsal on a recent copy of production data almost always finds something: an extension that is not available on the target, a configuration parameter that changed, or a script that assumes a host name. Fix the runbook, then rehearse again on a fresh copy of the data. Keep going until consecutive rehearsals meet every go criterion without manual improvisation, and time each step so the cutover duration comes from measurement. Record every deviation, including the ones you fixed, so the final runbook reflects what actually happened in the rehearsals.

Before the old cluster is retired, prove that point-in-time recovery works on the new one. Enable WAL archiving on the new cluster, take a base backup, let normal writes continue, and restore to a chosen target time in a separate environment. Check that the restored database starts, that it stops at the intended timestamp, and that your reconciliation queries match expected results. Run this once the new cluster has taken real write traffic, because archive settings are easy to omit when the cluster is rebuilt. Keep the old cluster until a restore has succeeded and archive retention covers your recovery window. If your plan uses incremental backups, test pg_combinebackup in the same exercise.

What makes a PostgreSQL major upgrade take longer

This table lists the factors that stretch a PostgreSQL major upgrade and shows how each one moves the schedule. Read the second column for the effect on the upgrade itself and the third for whether the item adds one-time work, ongoing operating work or both. The main takeaway is that data volume matters less than extensions, authentication changes, client reconnection and regulated test evidence, which tend to set the critical path.

Effort driverHow it changes the scheduleOne-time or ongoing
Data size and number of databasesLarger clusters lengthen dump, restore or link-mode checks, and each database adds catalog checks and object counts. Ask the team to measure a rehearsal copy of your largest database rather than estimating from disk size.One-time
Extensions to rebuild or upgradeEvery extension must have a build for the target major version. Extensions without a matching release can block the cutover date, so confirm versions before scheduling.One-time
Custom functions and application SQLChanged behavior in the target version can break views, functions and queries. Each affected object needs review, a fix and a retest, which often becomes the longest task.One-time
Authentication changesMoving from MD5 to SCRAM, or adding LDAP, certificate or OAuth methods, requires password re-hashing or client changes. Plan for client driver checks and a staged rollout.One-time, with ongoing policy review
Number of replicas and backup chainsEach standby must be rebuilt or re-pointed, and backup chains must be reset or verified against the new version. Retained base backups add storage and verification work for the life of the rollback window.One-time and ongoing
Downtime budgetA short cutover budget usually requires logical replication, which adds setup, conflict review and lag monitoring. A longer budget allows a simpler offline method but limits how quickly you can roll forward.One-time, with ongoing lag monitoring if replication is used
Client applications to reconnectEvery application, pooler and job scheduler needs a connection string, driver and credential update. Coordinating owners and change windows often takes more calendar time than the database work.One-time
Testing required by regulated workloadsAuditors and internal controls may expect documented test cases, reconciliation results and approved rollback steps. Confirm evidence requirements with your assessor before the test plan is written.One-time, with evidence retained
Old cluster retentionKeeping the previous major version available for rollback means running or storing it until the rollback window closes. This adds disk, patching and monitoring until it is decommissioned.Ongoing until decommissioned

How much effort, time and input does a PostgreSQL upgrade need from our team?

What actually drives the cost and effort of a PostgreSQL major upgrade?

The main drivers are the size and shape of your databases, the downtime your business will accept, and how many environments must be upgraded and tested. Data size affects how long a copy or restore takes, which matters most for pg_upgrade in copy mode. Extensions and custom code add compatibility checks, rebuilds and application testing. Downtime budget decides between a pg_upgrade cutover and a logical replication cutover, which needs more setup and monitoring. Number of environments multiplies rehearsal work, and compliance evidence such as change records, test results and sign-off history adds documentation time. Ask any provider to show how each of these changes the scope before you compare prices.

Which parts of a PostgreSQL upgrade are one-time and which recur?

Most of the upgrade work is one-time: inventory, compatibility checks, building and rehearsing the runbook, the cutover itself and post-upgrade verification. Recurring costs come afterward. You will need to keep PostgreSQL on a supported major version, apply minor releases, which the project ships at least once every three months, and repeat the upgrade process when the next major version is due. Each future upgrade is cheaper if the first one left you with a tested runbook, documented extension versions and automated checks. Ask whether a quote covers the first upgrade only or includes support for later minor and major updates.

Can our own database team complete a PostgreSQL major upgrade without outside help?

Yes, a team can complete the upgrade alone if three conditions hold. First, it has a tested runbook that covers pre-checks, the cutover steps and rollback. Second, it has time to rehearse the full procedure on a copy of production, not just read the documentation. Third, it has people who own the database, including someone who can make the go or no-go call during the change window. If any of these is missing, the risk moves into the cutover itself. An outside partner is useful when one of these gaps exists or when the team lacks capacity for rehearsal and testing alongside its normal work.

What do we need to provide during a PostgreSQL upgrade engagement?

The work depends on your access and your people more than on tooling. Access means accounts and network paths to the source and target servers, backup storage and monitoring, in your own environment. Application owners must test their workloads against the new version and confirm that queries, drivers and batch jobs behave as expected. A change window must be agreed in advance, with the business aware of the expected downtime. Sign-off on rollback criteria is required before the cutover, because someone must decide in advance what counts as a failed upgrade and when to return to the old version. Ask for these inputs to be listed by name and role in the written scope.

What should a written quote for a PostgreSQL upgrade include?

A useful quote states the scope in terms you can check. It should list the source and target versions, the upgrade method and the reason for choosing it, and the number of databases and environments in scope. It should name the extensions to be checked and the application tests included. It should describe the rehearsal, the cutover support, the rollback plan and the post-upgrade verification. It should show which items are one-time and which are optional ongoing support, state what you must provide, and describe what is excluded, such as application code changes or compliance evidence packages. DeployOpen scopes work in writing before it starts, and most engagements are fixed-scope, so the agreed scope is the basis for the price.

How long does a PostgreSQL major upgrade take?

The duration depends on the factors above, so no fixed figure applies to every database. The most reliable way to estimate it is to rehearse on a copy of production and time each step, including the restore or replication catch-up, extension rebuilds and verification queries. Use that measured time, not a general estimate, to plan the change window. Ask any provider to base its schedule on a rehearsal in your environment and to show which steps depend on data size. For the upgrade options and the downtime each one implies, check the vendor documentation for your target version and confirm the figures in your own test environment.

What do we need to confirm about extensions and custom code before the quote?

Confirm the list of installed extensions, their versions and whether each one supports your target PostgreSQL major version. Also list any custom functions, triggers, procedures and application queries that depend on behavior that may have changed. Your engineers should run the compatibility checks against a copy of the database and record the results. Extensions without a version for the target release, or custom code that relies on deprecated behavior, usually add the most scope. Include this inventory in your request for a quote so the provider can scope testing and rebuild work accurately.

How DeployOpen scopes, delivers and supports a PostgreSQL upgrade

DeployOpen starts by matching the upgrade method to your downtime budget, then builds and rehearses the cutover in your own infrastructure. Each engagement is fixed-scope, so the written scope settles which pg_upgrade mode or logical replication path applies, which systems are included and what rollback each option leaves. Ongoing support is available as a retainer.

How we scope

  • The written scope names the source and target major versions and the upgrade method chosen against your downtime budget.
  • It lists the databases, extensions, replicas, connection poolers and client authentication methods in the upgrade boundary.
  • Engagements are fixed-scope, and ongoing support after cutover can be taken on as a retainer.

How we build

  • Build a rehearsal on a copy of production, running pg_upgrade --check and fixing every reported incompatibility before cutover.
  • For logical replication, configure publications and subscriptions, check sequences and row counts, and time the switchover.
  • Document the rollback path for each option, noting that link mode changes the source cluster.

How we hand over

  • Runbooks with the exact commands, parameter files, maintenance window steps and go or no-go checks for the cutover.
  • Pre-upgrade and post-upgrade checks covering extension versions, statistics, authentication settings and application connections.
  • Knowledge transfer to your operators and an evidence pack showing test results, timings and the rollback decision record.

How we support

  • Post-cutover monitoring plan for replication lag, error logs and removal of old clusters after acceptance.
  • Ongoing support, upgrades and continuous testing are available as retainers for minor releases and later major versions.
  • Patch and upgrade work runs in your infrastructure on a schedule agreed in the written scope.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.