Upgrade to PostgreSQL 18

Upgrade the database of an existing Cloud Management Platform (CMP) installation from PostgreSQL 14 to PostgreSQL 18

PostgreSQL 14 reaches end of life in November 2026 and will no longer receive security or bug fixes. PostgreSQL 18 is supported until November 2030.

  • The upgrade is optional and separate. Upgrading CMP does not upgrade the database. CMP continues to work on PostgreSQL 14 until you upgrade.
  • New installations use PostgreSQL 18. No action is required for a new CMP installation.
  • The upgrade requires downtime. CMP is unavailable while the database is upgraded, so schedule the upgrade in a maintenance window.

Upgrade scripts

The scripts are included in CMP 2026.3.97 and later, in the top level of the unpacked installer and upgrader. Run each script from that directory. The PostgreSQL 18 packages are included in the upgrader, so the scripts work on servers without internet access and on database servers without CMP installed.

Script What it does
postgresql_upgrade.sh Assesses the database and, when asked, upgrades it. Also updates the PostgreSQL packages on servers that do not run the database.
verify_postgresql_upgrade.sh Checks a completed upgrade. Read-only and safe to run at any time.
confirm_postgresql_upgrade.sh Removes the PostgreSQL 14 data and packages once you are satisfied with the upgrade.
revert_postgresql_upgrade.sh Returns the database to PostgreSQL 14, if PostgreSQL 14 has not yet been removed.

Options for postgresql_upgrade.sh:

Option Effect
(none) Assessment only. Nothing is changed, and CMP stays in service.
--upgrade Upgrades the database on this server. CMP must already be stopped.
--upgrade-packages For a server that does not run the database, such as a web or job engine server, or a standby being rebuilt. Installs the PostgreSQL 18 packages and removes the PostgreSQL 14 packages.
--dbname NAME The CMP database name, if it is not cloudbolt.
-h, --help Shows usage.

Choose a procedure

Your deployment Procedure
A single CMP appliance with its own database Upgrade a single appliance
CMP on several servers, such as separate web and job engine servers, with the database on its own server Upgrade a distributed or high-availability deployment
A primary database server with one or more standby servers Upgrade a distributed or high-availability deployment
A database you manage yourself, including a cloud database service Upgrade the database with your own procedure while CMP is stopped. Then update each CMP server as described in Update the application servers.

If you archive the write-ahead log for point-in-time recovery, also read Point-in-time recovery before you start.

Before you begin

  • Take a full VM snapshot or operating system backup of every database server, and confirm you can restore it. This is required. In a high-availability deployment, include the standby servers. For an additional copy of the database and CMP files, see Back up Cloud Management Platform. It does not replace the snapshot.
  • Run every command as root. Log in as root, or use sudo su -. Do not run the scripts with sudo, because it changes the environment the scripts depend on. Commands that use sudo -u postgres are correct as written.
  • Do not remove the PostgreSQL 14 packages yourself. The upgrade needs them to read the existing database. Remove them afterward with confirm_postgresql_upgrade.sh.
  • Do not install the PostgreSQL 18 packages yourself. The scripts install them.

Upgrade a single appliance

Use this procedure when CMP and its database run on the same server. Assess the appliance ahead of time, then in a maintenance window stop CMP, upgrade the database, verify it, and return CMP to service. PostgreSQL 14 stays on disk until you remove it, so you can return to it if needed. Complete the steps in order.

Assess the appliance

The assessment reports the database size and the free space the upgrade needs on each filesystem. It changes nothing and does not stop CMP, so you can run it at any time.

./postgresql_upgrade.sh

Example report:

==============================================================
 CloudBolt PostgreSQL upgrade assessment
==============================================================
Generated:      2026-09-10 11:55:34 UTC
Appliance:      cloudbolt.example.com
PostgreSQL:     14 -> 18
Data directory: /var/lib/pgsql/14/data

Database
  name:           cloudbolt
  size:           1.9G
  all databases:  1.9G

Space needed, per filesystem
  /
      to copy:   1.9G
      needed:    2.3G
      available: 24G

A copy of each report is saved in /var/log/cloudbolt/install/.

  • Space needed. The database and the cloudbolt_data tablespace can be on different filesystems, and each is checked separately. If a filesystem is short of space, the report says which one and by how much. Extend or free space on it, then run the assessment again.
  • Downtime. The report does not estimate downtime, because it depends on your database size and storage. To plan your window, restore a copy of your database on a test server and time the upgrade there. As a guide, a 1.9 GB database upgraded in about one minute.
  • Compatibility. The assessment does not check compatibility. The upgrade checks it before anything is stopped, and does not continue if it finds a problem.

Stop CMP

Nothing can be connected to the database during the upgrade, so stop CMP first. CMP is unavailable until you return it to service. The upgrade does not start while anything is still connected, and it reports what is connected.

  1. Let running jobs finish if possible. To find jobs that are still running and cancel them, open the CMP shell:

    /opt/cloudbolt/manage.py shell_plus
    

    Then run:

    for j in Job.objects.filter(status="RUNNING"):
        print(j.id)
        j.status = "CANCELED"
        j.save()
    
  2. Stop the job engine and the web server:

    supervisorctl stop jobengine:*
    systemctl stop httpd
    

Upgrade the database

The upgrade installs PostgreSQL 18, checks compatibility, stops PostgreSQL 14, upgrades the database, carries over your PostgreSQL configuration, starts PostgreSQL 18, and confirms the database is available. If a check fails before PostgreSQL 14 is stopped, nothing has changed. If the script reports an error, see Troubleshooting.

./postgresql_upgrade.sh --upgrade

Verify the upgrade

The verification confirms that the database runs on PostgreSQL 18, that your configuration was carried over and is in effect, that the correct services are enabled, and that client tools such as psql and pg_dump use PostgreSQL 18. It compares against the PostgreSQL 14 files, so run it before you remove PostgreSQL 14. Every check should report OK.

./verify_postgresql_upgrade.sh

Return CMP to service

systemctl start httpd
supervisorctl start jobengine:*

Then confirm CMP works:

  • You can log in.
  • Servers, resources, groups, and blueprints appear as before.
  • A small order or resource action runs to completion.
  • Reports and dashboards load.

Remove PostgreSQL 14

The upgrade leaves the PostgreSQL 14 database on disk, so you can return to it with revert_postgresql_upgrade.sh without restoring a snapshot. Keep it until you are confident in the upgrade.

When you are ready, run the cleanup script. It lists each directory it will remove with its size, and asks you to type DELETE. It then asks separately whether to remove the PostgreSQL 14 packages. If another installed package still needs them, such as an older CMP package, they are left installed, and the script tells you which package needs them.

./confirm_postgresql_upgrade.sh

Upgrade a distributed or high-availability deployment

Use this procedure when CMP runs on more than one server, when the database has its own server, or when the database has standby servers. Upgrade the database on the primary server, provide the web and job engine servers with the PostgreSQL 18 client tools, and rebuild each standby as a copy of the upgraded primary. If you have no standby servers, skip Stop the standbys and Rebuild the standbys. Complete the steps in order.

Plan the upgrade

  • Database servers. Copy and unpack the CMP upgrader on the primary database server and on each standby. CMP does not need to be installed on them.
  • Application servers. Before you start, upgrade CMP on each web and job engine server to 2026.3.97 or later.
  • Snapshots. Snapshot the primary and every standby.
  • Standbys. PostgreSQL cannot replicate from version 18 to version 14, so each standby is rebuilt from the upgraded primary. There is no failover from the time you stop the standbys until you rebuild them, so plan the rebuild soon after the upgrade.
  • Replication details. Rebuilding a standby requires the primary’s address and the replication username and password used when the standbys were set up. If you do not have them, they are in the primary_conninfo line of /var/lib/pgsql/14/data/postgresql.auto.conf on each standby. Note them before the rebuild, which removes that directory.

Assess the primary

Run the assessment on the primary database server and read the report as described in Assess the appliance. While standbys are connected, the script lists them instead of the report. This is expected and is resolved when you stop the standbys. If you run the script on a standby, it tells you to run it on the primary and makes no changes.

./postgresql_upgrade.sh

Stop CMP

Stop CMP on every web and job engine server, as described in Stop CMP.

Stop the standbys

The primary cannot be upgraded while standbys replicate from it. A standby that uses a replication slot is listed even when stopped, and its slot must be removed before the upgrade. A standby without a slot is only detected while it is running, so make sure every standby is stopped, including any the script does not list.

  1. On each standby, stop PostgreSQL:

    systemctl stop postgresql-14
    
  2. On the primary, run the assessment again:

    ./postgresql_upgrade.sh
    
  3. If it lists standbys with replication slots, run the removal command it prints for each one, then run the assessment again. Continue when it shows the assessment report.

Upgrade the primary

Upgrade the database on the primary. Your replication settings, including the cloudbolt_conf files and the replication entries in pg_hba.conf, are carried over to PostgreSQL 18.

./postgresql_upgrade.sh --upgrade

Verify the upgrade

On the primary, run the verification. Every check should report OK.

./verify_postgresql_upgrade.sh

Update the application servers

The web and job engine servers still have the PostgreSQL 14 client tools. These cannot connect to a PostgreSQL 18 database, and the database backup taken by the next CMP upgrade would fail. On every web and job engine server, install the PostgreSQL 18 packages and remove the PostgreSQL 14 packages. The script confirms that psql and pg_dump now use PostgreSQL 18. Running it again on an already updated server makes no changes.

./postgresql_upgrade.sh --upgrade-packages

Return CMP to service

On every web and job engine server, start CMP and confirm it works, as described in Return CMP to service.

Rebuild the standbys

Rebuild each standby by replacing its PostgreSQL 14 database copy with a fresh PostgreSQL 18 copy from the primary. Rebuild one standby at a time, and confirm each one is replicating before you start the next. CMP can remain in service during this process. Run these commands on the standby unless stated otherwise.

  1. Keep PostgreSQL 14 from starting at boot:

    systemctl disable postgresql-14
    
  2. Install PostgreSQL 18. If the script says the PostgreSQL 14 packages were left installed because another package needs them, such as an older CMP package, that is expected. They are not used.

    ./postgresql_upgrade.sh --upgrade-packages
    
  3. Remove the old standby data, which is a PostgreSQL 14 copy of the database. The path below is the default tablespace location; if yours is different, use your path.

    rm -rf /var/lib/pgsql/14/data /var/opt/cloudbolt_pgsql/cloudbolt_data/PG_14_*
    
  4. Copy the database from the primary. This copies the database and its configuration, configures the server as a standby, and creates a replication slot on the primary. Replace PRIMARY_HOST and REPLICATION_USER with your replication details, and SLOT_NAME with a name for this standby, such as standby1. Use a different slot name for each standby, and keep a note of it: you need it again after a failover. Enter the replication password when asked.

    sudo -u postgres /usr/pgsql-18/bin/pg_basebackup -h PRIMARY_HOST -U REPLICATION_USER -D /var/lib/pgsql/18/data -R -C -S SLOT_NAME -X stream -P -c fast
    

    -c fast starts the copy straight away; without it, the command can wait several minutes with no output. If the command fails, it leaves nothing behind on the primary. Correct the problem and run it again.

  5. Start the standby:

    systemctl enable --now postgresql-18
    
  6. On the primary, confirm the standby is replicating. Its address should show streaming, and its slot should show t under active.

    sudo -u postgres psql -c "SELECT client_addr, state FROM pg_stat_replication"
    sudo -u postgres psql -c "SELECT slot_name, active FROM pg_replication_slots"
    

Remove PostgreSQL 14

When you are confident in the upgrade, remove PostgreSQL 14 from the primary as described in Remove PostgreSQL 14. The standbys need no further cleanup.

./confirm_postgresql_upgrade.sh

On a database server where an older CMP package is installed, the PostgreSQL 14 packages stay installed because that package needs them. They are not used. To remove them, upgrade CMP on that server, then run ./confirm_postgresql_upgrade.sh again on the primary, or ./postgresql_upgrade.sh --upgrade-packages on a standby.

Update failover procedures

After the upgrade, the service name and paths used in your failover procedures change:

Item PostgreSQL 14 PostgreSQL 18
Service postgresql-14 postgresql-18
Data directory /var/lib/pgsql/14/data /var/lib/pgsql/18/data
Programs /usr/pgsql-14/bin /usr/pgsql-18/bin

Your failover procedure also needs a step it may not have had before. Each rebuilt standby replicates through a replication slot on the primary. Slots are not copied to standbys, so a standby promoted to primary has none, and the other standbys cannot replicate from it. Their logs show replication slot "SLOT_NAME" does not exist. After you promote a standby, and before you point the other standbys at it, create a slot on the new primary for each of them, with the slot names they used before:

sudo -u postgres psql -c "SELECT pg_create_physical_replication_slot('SLOT_NAME');"

A standby that is already pointed at the new primary connects within a few seconds of its slot being created, without a restart.

Also clear the replication settings the promoted standby kept from its time as a standby. They do nothing on a primary, but a standby you later build from it with pg_basebackup copies them, and the leftover slot name stops that standby from replicating. On the new primary:

sudo -u postgres psql -c "ALTER SYSTEM RESET primary_conninfo;"
sudo -u postgres psql -c "ALTER SYSTEM RESET primary_slot_name;"

Point-in-time recovery

This section applies only if you archive the database’s write-ahead log (WAL) with archive_command for point-in-time recovery.

  • Your archiving settings are carried over, so PostgreSQL 18 continues to archive to the same location.
  • Take the base backup with PostgreSQL 18 tools, such as /usr/pgsql-18/bin/pg_basebackup, or with a backup product that supports PostgreSQL 18.
  • Keep your earlier backups for as long as your retention policy requires. You can use them to restore the database to its pre-upgrade state on PostgreSQL 14.

Troubleshooting

Upgrade failures

If the upgrade fails, the script stops and reports how far it got:

Where it stopped What to do
Before the database upgrade started PostgreSQL 14 is unchanged. Start it with systemctl start postgresql-14 and return CMP to service.
During the database upgrade PostgreSQL 14 is unchanged. Start it with systemctl start postgresql-14 and return CMP to service. Before you try again, remove /var/lib/pgsql/18/data and the PG_18_* directory in each tablespace.
After PostgreSQL 18 started The database is on PostgreSQL 18. Correct the problem named by the script, or revert to PostgreSQL 14.

Do not run the upgrade again until the database is running. When you contact CloudBolt Support, include /var/log/cloudbolt/install/postgresql_upgrade_*.log and the pg_upgrade_* directory next to it.

Revert to PostgreSQL 14

If the upgrade succeeded but you need to return to PostgreSQL 14, and you have not yet removed PostgreSQL 14, stop CMP on every server, then run the revert on the database server. In a high-availability deployment, run it on the primary.

./revert_postgresql_upgrade.sh

The script removes PostgreSQL 18 and its packages, leaving the server on PostgreSQL 14. You can run the upgrade again later.

In a high-availability deployment, a standby already rebuilt on PostgreSQL 18 cannot replicate from the reverted primary. The revert lists the standbys that were replicating from PostgreSQL 18 when it ran. Each one keeps running and logs database system identifier differs between the primary and standby until you rebuild it from the primary with your PostgreSQL 14 procedure, or restore it from its snapshot. Web and job engine servers updated with --upgrade-packages keep the PostgreSQL 18 client tools, which work with a PostgreSQL 14 database.

What the upgrade does not change

  • Your CMP version. Only the database is upgraded.
  • Your data. The database is upgraded in place. Nothing is migrated or discarded.
  • Your PostgreSQL configuration. postgresql.conf, postgresql.auto.conf, pg_hba.conf, pg_ident.conf, and the cloudbolt_conf directory are carried over, so your changes are kept. The CMP tuning file, cloudbolt_conf/01-cb-postgresql.conf, is regenerated for PostgreSQL 18, and any other files you added to cloudbolt_conf still apply.

Most query planner statistics carry over, so performance is normal right after the upgrade, and the upgrade regenerates the rest. To refresh all statistics afterward, you can run the following at any time without downtime:

sudo -u postgres /usr/pgsql-18/bin/vacuumdb --all --analyze-only --jobs=$(nproc)