Skip to main content
RunBook Academy

PostgreSQLII · Installation, Packaging and Service ManagementInstallation

Multiple clusters on one host

Intermediate⏱ ~25 minpsql

What you'll learn

  • Create and address a second cluster on a host that already runs one
  • State which resources separate clusters isolate and which they still share
  • Avoid the failure modes specific to multi-cluster hosts
  • Decide between separate clusters, separate databases and separate hosts

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

The first lesson of this course established that databases inside one cluster are tenants rather than isolated services: they share a restart window, a connection budget, a write-ahead log and a restore point. When those shared properties are the problem, the answer is a second cluster.

A second cluster on the same host is genuinely a second server. It has its own postmaster, its own data directory, its own port, its own configuration, its own WAL and its own version. Two clusters on one machine share nothing that PostgreSQL manages.

Creating one

On Debian and Ubuntu the packaging makes this a single command, because the layout was designed for it.

Configuration changea second cluster alongside an existing one
$ pg_createcluster 18 reporting
selecting default "shared_buffers" ... 128MB
selecting default time zone ... Etc/UTC
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
Ver Cluster   Port Status Owner    Data directory                   Log file
18  reporting 5433 down   postgres /var/lib/postgresql/18/reporting /var/log/postgresql/postgresql-18-reporting.log

Elsewhere, the same result is initdb into a new directory plus a service unit and a port assignment done by hand:

# The manual equivalent, on any layout.
NEWDATA=/var/lib/pgsql/18/reporting
initdb --pgdata="$NEWDATA" --encoding=UTF8 --data-checksums
# Then set port = 5433 in that cluster's postgresql.conf,
# and create a service unit that passes -D "$NEWDATA".

The work the wrapper saves is not the initdb; it is remembering to allocate a free port, to give the cluster a distinct log file, and to create a unit that will start it at boot.

Addressing the right one

Every client tool needs to be told which cluster it means, and the mechanism is the port or the socket.

# By port, over TCP
psql -h 127.0.0.1 -p 5433 -U postgres -c 'SHOW data_directory'

# By port, over the Unix socket directory
psql -h /var/run/postgresql -p 5433 -U postgres -c 'SHOW data_directory'

# By environment, which is how scripts should do it
export PGPORT=5433
psql -U postgres -c 'SHOW data_directory'
Read-only / Safetwo clusters answering for themselves on one host
$ psql -p 5433 -tAc 'SHOW data_directory'; psql -p 5432 -tAc 'SHOW data_directory'
/var/lib/postgresql/18/reporting
/var/lib/postgresql/18/docker

SHOW data_directory is the confirmation step that belongs at the top of any procedure run on a multi-cluster host. The port you passed is what you asked for; the data directory is what you got, and on a host where a colleague has changed a port assignment those are not always the same.

What is isolated, and what is not

This is the table that decides whether a second cluster solves your problem.

Isolated by a separate clusterStill shared
Restart and reload windowsCPU
max_connections budgetPhysical memory
Configuration, including shared_buffersThe OS page cache
The write-ahead logDisk bandwidth and IOPS
Backup and restore pointThe filesystem, and its free space
Major versionKernel limits: file descriptors, shared memory, semaphores
Roles and authenticationThe network interface
Crash blast radiusThe host itself

The left column is why you would do it. The right column is why it is not a substitute for a second machine.

A reporting cluster that runs an enormous analytical query will not consume the transactional cluster’s connection slots or force it to restart, and that is a real and valuable separation. It will absolutely consume the disk bandwidth, the page cache and the CPU that the transactional cluster was relying on.

The failure modes specific to multi-cluster hosts

Port collisions and reassignments. A cluster whose port is changed without updating the clients that reach it fails in a way that looks like an outage. Worse, if two clusters swap ports, connections succeed and reach the wrong database. inet_server_port() and SHOW data_directory are the defence.

Kernel limits are shared and additive. Each cluster wants file descriptors, semaphores and shared memory. A host sized for one cluster can refuse to start the second, and the error names the kernel resource rather than PostgreSQL. Part XI covers the specific limits.

Memory over-commitment is easy and silent. Two clusters each configured with shared_buffers at a quarter of host memory are using half of it before a single query runs, and each will additionally allocate work_mem per operation per backend. The OOM killer resolves this eventually and badly.

Backups multiply. Each cluster needs its own backup configuration, its own WAL archive destination and its own restore test. A second cluster that nobody added to the backup schedule is the most common serious consequence, and it is invisible until a restore is needed.

Log files diverge. Each cluster writes its own log. A log aggregation configuration that names one file silently stops covering the estate the moment a second cluster exists.

Choosing between the three options

RequirementSeparate databasesSeparate clustersSeparate hosts
Logical separation of data
Independent connection budget
Independent restart window
Independent restore point
Different major versions
Independent CPU, memory, disk
Survives host loss
Cross-database transactions

Note the last row. Transactional consistency across the boundary is lost as soon as you leave a single database, and it does not come back at any of the higher tiers. That is the cost to weigh against everything in the left column, and it is the reason not to split an application’s own data.

The genuinely common good use for a second cluster is a major version upgrade: pg_upgrade requires both versions present, and for the duration of the upgrade you have two clusters on one host by construction. Part XVII covers that case in full.

Production discipline

  1. Confirm the target before every destructive command. SHOW data_directory and inet_server_port() cost nothing and are the only reliable evidence of which cluster you reached.
  2. Add every new cluster to backup, monitoring and log aggregation on the day it is created. A cluster nobody backs up is the failure that surfaces at restore time.
  3. Do not use separate clusters to solve resource contention. They isolate scheduling and failure, not CPU, memory or disk, and two buffer pools cache the same data twice.
  4. Sum shared_buffers across all clusters before sizing the host, and remember work_mem is allocated per operation per backend on top of that.
  5. Set PGPORT explicitly in scripts rather than relying on the default, so that a script cannot silently address the wrong cluster.

Cross-course references

  • Linux for Production Sysadmins — Part XXXVII (Resources) covers the kernel limits that two clusters share and Part VII (systemd) covers writing the unit a manually created cluster needs.
  • Docker & Containers — Part XV (Resource controls) covers bounding what a workload may consume, which is the actual remedy for the contention that separate clusters do not solve.
  • Proxmox — Part IX (VMs) covers the case where separate hosts is the right answer and the hosts are virtual.

Quiz

Knowledge check · 6 questions

  1. Q1. A reporting workload is slowing the transactional workload on a shared cluster. The team proposes moving reporting into a second PostgreSQL cluster on the same host. What will this achieve?

  2. Q2. Which function is most useful for confirming which cluster you have actually connected to on a multi-cluster host?

  3. Q3. Which of these are genuinely isolated between two PostgreSQL clusters running on the same host? Select all that apply.

  4. Q4. Two PostgreSQL clusters on one host can participate in a single transaction spanning both.

  5. Q5. Name three operational systems that must be updated on the day a second cluster is created, and say what fails if each is missed.

  6. Q6. Explain what happened and what should have prevented it.

    A host runs two PostgreSQL 18 clusters: main on 5432 carrying production, and staging on 5433. During a data refresh an engineer intended to drop and recreate a database on staging. They set PGPORT=5433 in their shell, then opened a new terminal window to check something, returned to work, and ran DROP DATABASE app followed by a restore from a staging dump. Production reports the application database missing. The engineer is certain they set the port correctly.

Passing score: 75%. Answers are checked in this browser.