PostgreSQLII · Installation, Packaging and Service ManagementInstallation
Multiple clusters on one host
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
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.
$ pg_createcluster 18 reportingselecting 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.logElsewhere, 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'
$ psql -p 5433 -tAc 'SHOW data_directory'; psql -p 5432 -tAc 'SHOW data_directory'/var/lib/postgresql/18/reporting
/var/lib/postgresql/18/dockerSHOW 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 cluster | Still shared |
|---|---|
| Restart and reload windows | CPU |
max_connections budget | Physical memory |
Configuration, including shared_buffers | The OS page cache |
| The write-ahead log | Disk bandwidth and IOPS |
| Backup and restore point | The filesystem, and its free space |
| Major version | Kernel limits: file descriptors, shared memory, semaphores |
| Roles and authentication | The network interface |
| Crash blast radius | The 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
| Requirement | Separate databases | Separate clusters | Separate 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
- Confirm the target before every destructive command.
SHOW data_directoryandinet_server_port()cost nothing and are the only reliable evidence of which cluster you reached. - 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.
- 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.
- Sum
shared_buffersacross all clusters before sizing the host, and rememberwork_memis allocated per operation per backend on top of that. - Set
PGPORTexplicitly 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
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?
Q2. Which function is most useful for confirming which cluster you have actually connected to on a multi-cluster host?
Q3. Which of these are genuinely isolated between two PostgreSQL clusters running on the same host? Select all that apply.
Q4. Two PostgreSQL clusters on one host can participate in a single transaction spanning both.
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.
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.