PostgreSQL – pg_upgrade from 10 to 12
Tags: postgres, database, infrastructure
Published: 2020-03-31 23:27:09

---
title: PostgreSQL – pg_upgrade from 10 to 12
published: true
date: 2020-03-31 14:20:19 UTC
tags: PostGreSQL,database,infrastructure
canonical_url: 
---

I have some PostgreSQL databases running pretty well but we need to keep our software updated. This is a mandatory practice for a high-quality service. Those servers are running version 10 and they need to be upgraded to version 12. I have used `pg_dump` / `pg_restore` strategy for a long time, but this time I would rather use `pg_upgrade`.

Let's dive into how to do it.

Table of contents:

1. Install
2. InitDB
3. Check upgrade consistency
4. Set locale
5. Upgrade
6. Configurations

## Install

The package `postgresql12-server` contains everything needed to run the server, but my databases use some extensions [1], then I will add `postgresql12-devel` and `postgresql12-contrib` to be able to compile and to install the extensions.

```
yum install postgresql12-server postgresql12-devel postgresql12-contrib
```

## InitDB

After installation we need to setup new server with initdb:

```
~% /usr/pgsql-12/bin/postgresql-12-setup initdb
Initializing database … OK
```

## Check upgrade consistency

We need to check compatibility. Turn to postgres user (`su - postgres`) and run the command:

```bash
~% su - postgres
~% /usr/pgsql-12/bin/pg_upgrade --old-bindir=/usr/pgsql-10/bin --new-bindir=/usr/pgsql-12/bin --old-datadir=/var/lib/pgsql/10/data --new-datadir=/var/lib/pgsql/12/data --check

Performing Consistency Checks on Old Live Server
------------------------------------------------
Checking cluster versions ok
Checking database user is the install user ok
Checking database connection settings ok
Checking for prepared transactions ok
Checking for reg* data types in user tables ok
Checking for contrib/isn with bigint-passing mismatch ok
Checking for tables WITH OIDS fatal

Your installation contains tables declared WITH OIDS, which is not supported
anymore. Consider removing the oid column using
    ALTER TABLE ... SET WITHOUT OIDS;
A list of tables with the problem is in the file:
    tables_with_oids.txt

Failure, exiting
```

As you may see, I got a fatal error, indicating that the upgrade is not possible. In my case, tables with OIDs are the culprit. In your case could be something else. In any case, we need to fix before upgrading.

I fixed tables removing OIDs on mentioned tables. And ran check again:

```
Performing Consistency Checks on Old Live Server
------------------------------------------------
Checking cluster versions ok
Checking database user is the install user ok
Checking database connection settings ok
Checking for prepared transactions ok
Checking for reg* data types in user tables ok
Checking for contrib/isn with bigint-passing mismatch ok
Checking for tables WITH OIDS ok
Checking for invalid "sql_identifier" user columns ok
Checking for presence of required libraries ok
Checking database user is the install user ok
Checking for prepared transactions ok

*Clusters are compatible*
```

Yay!

## Set locale

There is a tricky configuration that is not detected by `pg_upgrade check` but it is very important to me. I use `C` locale on my databases [2], then I need to perform an extra step. If this is your case, you may follow the same steps applying yours.

I need to stop postgresql10 and start postgresql12:

```
systemctl stop postgresql-10.service
systemctl start postgresql-12.service
```

Then I run locale change at my template1 then locale will be enabled when my database will be upgraded.

```sql
UPDATE pg_database SET datcollate='C', datctype='C' WHERE datname='template1';
```

And stop again: `systemctl stop postgresql-12.service` to be ready to upgrade.

## Upgrade

Upgrade command is the same that we run before, without `--check` flag.

```bash
~% su - postgres
~% /usr/pgsql-12/bin/pg_upgrade --old-bindir=/usr/pgsql-10/bin --new-bindir=/usr/pgsql-12/bin --old-datadir=/var/lib/pgsql/10/data --new-datadir=/var/lib/pgsql/12/data

Performing Consistency Checks
-----------------------------
Checking cluster versions ok
Checking database user is the install user ok
Checking database connection settings ok
Checking for prepared transactions ok
Checking for reg* data types in user tables ok
Checking for contrib/isn with bigint-passing mismatch ok
Checking for tables WITH OIDS ok
Checking for invalid "sql_identifier" user columns ok
Creating dump of global objects ok
Creating dump of database schemas
                                                            ok
Checking for presence of required libraries ok
Checking database user is the install user ok
Checking for prepared transactions ok

If pg_upgrade fails after this point, you must re-initdb the
new cluster before continuing.

Performing Upgrade
------------------
Analyzing all rows in the new cluster ok
Freezing all rows in the new cluster ok
Deleting files from new pg_xact ok
Copying old pg_xact to new server ok
Setting next transaction ID and epoch for new cluster ok
Deleting files from new pg_multixact/offsets ok
Copying old pg_multixact/offsets to new server ok
Deleting files from new pg_multixact/members ok
Copying old pg_multixact/members to new server ok
Setting next multixact ID and offset for new cluster ok
Resetting WAL archives ok
Setting frozenxid and minmxid counters in new cluster ok
Restoring global objects in the new cluster ok
Restoring database schemas in the new cluster
                                                            ok
Copying user relation files
                                                            ok
Setting next OID for new cluster ok
Sync data directory to disk ok
Creating script to analyze new cluster ok
Creating script to delete old cluster ok

Upgrade Complete
----------------
Optimizer statistics are not transferred by pg_upgrade so,
once you start the new server, consider running:
    ./analyze_new_cluster.sh

Running this script will delete the old cluster's data files:
    ./delete_old_cluster.sh
```

Consider running analyze\_new\_cluster. Optional but nice to have.

```bash
vacuumdb: processing database "mydb": Generating minimal optimizer statistics (1 target)
vacuumdb: processing database "postgres": Generating minimal optimizer statistics (1 target)
vacuumdb: processing database "template1": Generating minimal optimizer statistics (1 target)
vacuumdb: processing database "mydb": Generating medium optimizer statistics (10 targets)
vacuumdb: processing database "postgres": Generating medium optimizer statistics (10 targets)
vacuumdb: processing database "template1": Generating medium optimizer statistics (10 targets)
vacuumdb: processing database "mydb": Generating default (full) optimizer statistics
vacuumdb: processing database "postgres": Generating default (full) optimizer statistics
vacuumdb: processing database "template1": Generating default (full) optimizer statistics

Done
```

## Configurations

Before deleting your old cluster, remember to get some of your configurations.

```
mv /var/lib/pgsql/12/data/pg_hba.conf /var/lib/pgsql/12/data/pg_hba.conf.new
cp /var/lib/pgsql/10/data/pg_hba.conf /var/lib/pgsql/12/data/
```

And add

```
# Add settings for extensions here
include_dir = '/var/lib/pgsql/conf.d' # include files ending in '.conf' from
```

Then you may delete your old cluster. ![🙂](https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f642.png)

Links:

1. Extensions: [https://www.postgresql.org/docs/current/contrib.html](https://www.postgresql.org/docs/current/contrib.html)
2. Locale: [https://www.postgresql.org/docs/current/locale.html](https://www.postgresql.org/docs/current/locale.html)