Upgrading the Version of a Heroku Postgres Database
Last updated May 29, 2025
Table of Contents
This article describes how to upgrade the major Postgres version of a Heroku Postgres database. The most recent major Postgres version supported by Heroku is 17.
Users can’t update a database’s minor version themselves. If a new minor version is available and the database is on an older minor version, Heroku automatically updates the minor version after each database maintenance on Standard-tier and higher plans.
You can only upgrade your major Postgres version via the Heroku CLI. It’s a significant operation that you must do with care.
Heroku supports three methods for upgrading the Postgres version of your database. All methods require some application downtime to ensure that no data is lost during the upgrade.
Upgrade Method | Description |
---|---|
`pg:upgrade:*` commands (recommended) | Works for all Heroku Postgres plans and is the recommended method. Requires downtime of about 5-10 minutes for most use cases, although this amount can vary. |
Follower database | Works for all Heroku Postgres plans except for Essential-tier plans. Requires downtime of about 30 minutes for most use cases, although this amount can vary. |
`pg:copy` |
Only works for Essential, Standard, Premium, or Private-tier Heroku Postgres plans that are under 10 GB.
Not supported for Shield-tier plans because PGBackups don’t work with Shield databases. Requires downtime of about 3 minutes per GB for most use cases, although this amount can vary substantially. |
You can upgrade your database to versions 15, 16, and 17. Use the --version
flag to specify the version to upgrade to. For example, add --version 16
to upgrade to Postgres 16. If you don’t set the --version
flag, the upgrade defaults to the latest version.
The upgrade process can fail due to out-of-memory errors for databases with a large number of schemas. If your database has more than 1,000 schemas or stores more than 10,000 objects, test the upgrade in advance and open a Support ticket for assistance if the upgrade fails.
Upgrading with pg:upgrade:* Commands
You can use the pg:upgrade:*
commands to perform version upgrades on Essential-tier databases, Standard-tier and higher leader databases, and follower databases.
The upgrade commands use the PostgreSQL pg_upgrade utility to upgrade your Postgres version in-place. Performing version upgrades with these commands requires app downtime of around 5-10 minutes for most use cases.
Essential-Tier and Followers
We’re changing the pg:upgrade
CLI command for Postgres version upgrades. While you can still use pg:upgrade
until its end-of-life, we recommend using the new upgrade commands to upgrade your Postgres version. See this Help article for more details.
This method is supported for all Essential-tier Heroku Postgres plans and follower databases. Using this method on a follower database unfollows the leader database before upgrading the follower’s Postgres version.
To upgrade the version, run pg:upgrade:run
directly on your database:
$ heroku pg:upgrade:run HEROKU_POSTGRESQL_RED --app example-app
Standard-Tier and Higher
To upgrade your database version with the upgrade commands:
- Run
pg:upgrade:prepare
to prepare your leader database for upgrade and schedule it during the next available maintenance window. - Wait until the scheduled maintenance for the upgrade, or run
pg:upgrade:run
on the leader database to start the prepared upgrade.
You can test the version upgrade beforehand with the pg:upgrade:dryrun
command.
1. Prepare Your Version Upgrade
You can’t use this command on a follower database or an Essential-tier database because those databases don’t upgrade through maintenance windows.
To being, run pg:upgrade:prepare
on your leader database:
$ heroku pg:upgrade:prepare HEROKU_POSTGRESQL_RED --app example-app
This command prepares the upgrade and schedules it for the next available maintenance window. You receive an email notification when the upgrade is prepared and scheduled. You can check the status of the upgrade with pg:upgrade:wait
or pg:info
. For example, with pg:upgrade:wait
:
$ heroku pg:upgrade:wait HEROKU_POSTGRESQL_RED --app example-app
Waiting for database postgresql-crystalline-69217... ⣟ preparing service for upgrade
You can cancel your prepared upgrade before the scheduled maintenance begins or before you start the upgrade with pg:upgrade:cancel
.
2. Run Your Version Upgrade
During the upgrade, your database loses connection and your app can’t access the database. Additionally, if you use Heroku Connect to sync Salesforce data with your database, to sync Salesforce data with your database, Heroku Connect can’t connect to your database during the upgrade. If any sync processes are impacted, your connection will be in the DB_UNAVAILABLE
error state. You can recover your connection after the version upgrade is finished to resume synchronization, or you can pause your Heroku Connect connection before the upgrade starts to avoid the DB_UNAVAILABLE
state.
After your upgrade is prepared and scheduled, you can either wait until the maintenance window for the upgrade to start automatically, or start the version upgrade manually on your leader database with the command:
$ heroku pg:upgrade:run HEROKU_POSTGRESQL_RED --app example-app
You can’t cancel the upgrade after starting it. This command also upgrades any attached follower databases. It takes some time to upgrade all followers.
You can check the status of the upgrade with pg:upgrade:wait
:
$ heroku pg:upgrade:wait HEROKU_POSTGRESQL_RED --app example-app
Waiting for database postgresql-crystalline-69217... ⣟ (1/8) checking upgrade service
If you paused your Heroku Connect connection, make sure you resume the Heroku Connect connection after the version upgrade is complete.
Upgrading with a Follower Database
We’re changing the pg:upgrade
CLI command for Postgres version upgrades. While you can still use pg:upgrade
until its end-of-life, we recommend using the new upgrade commands to upgrade your Postgres version. See this Help article for more details.
Performing a version upgrade with a follower database involves upgrading a follower of your database and promoting it as your new, upgraded database. With this method, you perform the upgrade on a separate add-on and your old database remains available after the upgrade. Performing an upgrade with a follower database requires app downtime on the order of 30 minutes.
If you must upgrade both the Postgres version and your plan, provision a new follower on a different plan and use pg:upgrade:run
as part of the changeover process.
You can test the version upgrade using this method beforehand with a forked database.
If you use Heroku Connect to sync Salesforce data with your database, see the instructions for upgrading the Heroku Postgres database version with a follower database.
If you use Streaming Data Connectors , see the instructions for the instructions for upgrading the Heroku Postgres database version with a follower database.
1. Provision a Follower Database
We recommend creating your upgrade target follower at least 24 hours in advance before running pg:upgrade:run
.
To begin, create a follower for your database and wait for the follower to catch up to the leader database. In the example, a follower with a standard-2
plan is created on the HEROKU_POSTGRESQL_LAVENDER_URL
. You can provision the plan best suited for your needs. Replace HEROKU_POSTGRESQL_LAVENDER_URL
with the config var of the database you’re upgrading.
The addons:create
example follows the syntax for Heroku CLI v9.0.0 or later. If you’re on v8.11.5 or earlier, use the command:
$ heroku addons:create heroku-postgresql:standard-2 --follow HEROKU_POSTGRESQL_LAVENDER_URL --app example-app
$ heroku addons:create heroku-postgresql:standard-2 --app example-app -- --follow HEROKU_POSTGRESQL_LAVENDER_URL
Adding heroku-postgresql:standard-2 to example-app... done, v71 ($200/mo)
Attached as HEROKU_POSTGRESQL_WHITE
Follower will become available for read-only queries when up-to-date
Use `heroku pg:wait` to track status
$ heroku pg:wait
Waiting for database HEROKU_POSTGRESQL_WHITE_URL... performing final cleanup steps after upgrade
The follower is considered “caught up” when it is within 200 commits of the primary database. You can check how many commits the follower is behind with the pg:info
command. See the Behind By
row of the follower database:
$ heroku pg:info --app example-app
=== HEROKU_POSTGRESQL_LAVENDER
Plan: Standard 0
Status: available
...
=== HEROKU_POSTGRESQL_WHITE
Plan: Standard 2
Status: available
...
Following: HEROKU_POSTGRESQL_LAVENDER (DATABASE_URL)
Behind By: 125 commits
2. Enter Maintenance Mode to Prevent Database Writes
It’s important that no new data is written to your current primary database during the upgrade process, because it doesn’t transfer to the new database. To accomplish this, place your app into maintenance mode. If you have scheduler jobs running as well, disable them. Databases continue to accrue billing hours while in maintenance mode.
Maintenance mode doesn’t automatically scale down dynos. Scale down web and any non-web dynos (for example, heroku ps:scale worker=0
) to ensure that no connections are writing data to the database.
Your application is unavailable starting at this point in the upgrade process.
$ heroku maintenance:on --app example-app
Enabling maintenance mode for example-app... done
3. Upgrade the Follower Database
Now that you are in maintenance mode and no additional data is being written to the primary database, you can upgrade the follower database.
Wait for the follower database to fully catch up to the primary as indicated by being behind by 0 commits
.
$ heroku pg:info --app example-app
=== HEROKU_POSTGRESQL_LAVENDER_URL
Plan: Standard 0
Status: available
...
=== HEROKU_POSTGRESQL_WHITE_URL
Plan: Standard 2
Status: available
...
Following: HEROKU_POSTGRESQL_LAVENDER_URL (DATABASE_URL)
Behind By: 0 commits
If you don’t wait for the follower to catch up then you get an error message:
▸ database is too far behind its leader. Wait until your follower catches up with its leader and try again.
When the follower is caught up, use the pg:upgrade:run
command to upgrade the Postgres version of the follower in place. Upgrading also causes the follower to unfollow the primary database. This step usually requires about 20 minutes to complete.
$ heroku pg:upgrade:run HEROKU_POSTGRESQL_WHITE --app example-app
You can monitor the progress of the upgrade with pg:upgrade:wait
or pg:wait
:
$ heroku pg:upgrade:wait --app example-app
Waiting for database HEROKU_POSTGRESQL_WHITE_URL... performing final cleanup steps after upgrade
As part of the pg:upgrade:run
process, Heroku Postgres runs ANALYZE
on your database. This process recalculates statistics for your database to make sure the Postgres query planner has up-to-date information even after a version upgrade. All credentials and custom credentials are also rotated as a part of the upgrade process.
The pg:upgrade:run
command can fail due to errors such as incompatible data types in a table in your database. If your upgrade fails, running pg:upgrade:wait
or pg:wait
returns version upgrade error, check your Heroku email notifications for details
. You can restart the upgrade after resolving the error.
Versions of Rails before 5.0 have a known compatibility issue with Postgres 10 and above. To work around this issue, upgrade your version of Rails or use the monkey patch suggested in the Rails issue.
4. Promote or Attach the New Database
If DATABASE_URL
was the config var for your previous primary database, use pg:promote
to promote the newly upgraded database as the new DATABASE_URL
. pg:promote
creates an alternate attachment for the old primary database, assigned with a new HEROKU_POSTGRESQL_<color>_URL
config var. The promotion process triggers a release and restarts the app.
$ heroku pg:promote HEROKU_POSTGRESQL_WHITE --app example-app
Promoting HEROKU_POSTGRESQL_WHITE_URL to DATABASE_URL... done
Now the follower database you created in step 1 is the primary database (DATABASE_URL
) for the app, although the app isn’t receiving new requests yet.
If the database you’re upgrading has a different config var other than the default DATABASE_URL
, use heroku addons:attach to promote your newly upgraded database with the required alias or attachment name. If you attached your original primary database to multiple apps, you must attach your new upgraded database to those apps with addons:attach
.
After the promotion, followers of your original primary database don’t automatically start to follow your new primary.
Create followers for the new primary database as needed. If you’re using Heroku CLI v9.0.0 or later, run the command:
$ heroku addons:create heroku-postgresql:standard-0 -a example-app -- --follow DATABASE_URL
If you’re using Heroku CLI v8.11.5 and earlier, run the command:
$ heroku addons:create heroku-postgresql:standard-0 --follow DATABASE_URL --app example-app
Be sure to deprovision your old followers after you no longer need them.
If your old primary was using connection pooling, and it was attached with the default name DATABASE_CONNECTION_POOL
, the promote reattaches the connection pooler to the new primary under the same name DATABASE_CONNECTION_POOL
.
Attachments under non-default names aren’t reattached. You must activate connection pooling on your new primary if you wish to keep using connection pooling on your new primary with the same non-default name as the old primary:
$ heroku pg:connection-pooling:attach DATABASE_URL --as MY_DATABASE_CONNECTION_POOL -a example-app
5. Exit Maintenance Mode
To resume normal application operation, scale any non-web dynos back to their original levels (for example, heroku ps:scale worker=1
).
Finally, turn off maintenance mode:
$ heroku maintenance:off --app example-app
Your application is now receiving requests to your upgraded database instance. You can confirm this by running heroku pg:info
. The database denoted by DATABASE_URL
is considered the primary database.
If your Heroku Postgres database isn’t connected to a Heroku application, you must retrieve the HEROKU_POSTGRESQL_WHITE_URL
and update your application to use it as your primary database.
Upgrading with pg:copy
The pg:copy
upgrade method uses native PostgreSQL backup and restore utilities. Instead of writing a database backup to disk, it streams the backup data directly to the restore process of a newly provisioned database. This process helps reduce bloat, the extra space taken up by dead rows on your database, and saves disk space.
The pg:copy
method requires approximately 3 minutes of app downtime per GB of your current database, although this amount can vary substantially depending on your schema and database plan. You can estimate your required downtime by testing the upgrade (perform the upgrade process on a new database on a non-production application).
The pg:copy
method supports upgrades between all supported Heroku Postgres plans and versions.pg:copy
only copies your default credential and the data it has access to. Any additional credentials and data that only they can access don’t get copied. You can also test the version upgrade using this method beforehand.
For Essential-tier databases that use the scheduled backups feature, your schedules are lost after upgrading to production-tier plans. Set up your schedules again after the upgrade to avoid missing a backup.
1. Provision a New Database
Provision a new Heroku Postgres database with your desired plan (in the example below the standard-0
plan is used, but you can provision the plan best suited for your needs):
$ heroku addons:create heroku-postgresql:standard-0 --app example-app
Adding heroku-postgresql:standard-0 on example-app... done, v122 ($50/mo)
The database should be available in 3-5 minutes
If you want to upgrade your database to a version of PostgreSQL other than the most recent supported version, specify the version to use with the --version
flag (for example, --version 15
).
Standard, Premium, and Private-tier databases take a few minutes to provision. You can use the pg:wait
command to notify you when provisioning is complete:
$ heroku pg:wait -a example-app
Waiting for database HEROKU_POSTGRESQL_PINK_URL... performing final cleanup steps after upgrade
2. Enter Maintenance Mode to Prevent Database Writes
It’s important that no new data is written to your current primary database during the upgrade process, because it doesn’t transfer to the new database. To accomplish this, place your app into maintenance mode. If you have scheduler jobs running as well, disable them.
Maintenance mode doesn’t automatically scale down dynos. Scale down web and any non-web dynos (for example, heroku ps:scale worker=0
) to ensure that no connections are writing data to the database.
Your application is unavailable starting at this point in the upgrade process.
$ heroku maintenance:on -a example-app
Enabling maintenance mode for example-app... done
3. Transfer Data to the New Database
To copy data from your current database to the newly provisioned database, use the pg:copy
command with the HEROKU_POSTGRESQL_COLOR
name of your new database.
In this example, the DATABASE_URL
is the source of the data in the transfer and HEROKU_POSTGRESQL_PINK
is the target database.
$ heroku pg:copy DATABASE_URL HEROKU_POSTGRESQL_PINK --app example-app
! WARNING: Destructive Action
! Transfering data from DATABASE_URL to HEROKU_POSTGRESQL_PINK
! This command will affect the app: example-app
! To proceed, type "example-app" or re-run this command with --confirm example-app
> example-app
You can also use the add-on name of your new database, for example, postgresql-concave-52656
:
$ heroku pg:copy DATABASE_URL postgresql-concave-52656 --app example-app
4. Promote or Attach the New Database
If DATABASE_URL
was the config var for your previous primary database, use pg:promote
to promote the newly upgraded database as the new DATABASE_URL
. pg:promote
creates an alternate attachment for the old primary database, assigned with a new HEROKU_POSTGRESQL_<color>_URL
config var. The promotion process triggers a release and restarts the app.
$ heroku pg:promote HEROKU_POSTGRESQL_PINK --app example-app
Promoting HEROKU_POSTGRESQL_PINK_URL to DATABASE_URL... done
Now the database you created in step 1 is the primary database (DATABASE_URL
) for the app, although the app isn’t receiving new requests yet.
If the database you’re upgrading has a different config var other than the default DATABASE_URL
, use heroku addons:attach to promote your newly upgraded database with the required alias or attachment name. If you attached your original primary database to multiple apps, you must attach your new upgraded database to those apps with addons:attach
.
After the promotion, followers of your original primary database don’t automatically start to follow your new primary.
Create followers for the new primary database as needed. If you’re using Heroku CLI v9.0.0 or later, run the command:
$ heroku addons:create heroku-postgresql:standard-0 -a example-app -- --follow DATABASE_URL
If you’re using Heroku CLI v8.11.5 and earlier, run the command:
$ heroku addons:create heroku-postgresql:standard-0 --follow DATABASE_URL -a example-app
Be sure to deprovision your old followers after you no longer need them.
5. Exit Maintenance Mode
To resume normal application operation, scale any non-web dynos back to their original levels (for example, heroku ps:scale worker=1
).
Finally, turn off maintenance mode:
$ heroku maintenance:off --app example-app
Your application is now receiving requests to your new database instance. You can confirm this by running heroku pg:info
. The database denoted by DATABASE_URL
is considered the primary database.
If your Heroku Postgres database isn’t connected to a Heroku application, you must retrieve the HEROKU_POSTGRESQL_WHITE_URL
and update your application to use it as your primary database.
Deprovisioning the Old Primary Database
After you upgrade your database, be sure to deprovision your old primary database:
$ heroku addons:destroy HEROKU_POSTGRESQL_LAVENDER --app example-app
Dataclips that were associated with the old primary database must be reassigned to the new database. Follow the instructions on Dataclip recovery to resolve any recoverable Dataclips.