KB
Databases

PostgreSQL 12 Streaming Replication Setup (Ubuntu 20.04)

5 min read1073 words38 code blocks

At a glance#

  • Purpose: Configure streaming replication from a PostgreSQL primary to a standby server.
  • Applies to: PostgreSQL 12 on Ubuntu 20.04.
  • Risk: High - requires a base backup and restart of both servers.
  • Time: 1-2 hours.

Overview#

This guide explains how to set up PostgreSQL 12 streaming replication between two Ubuntu 20.04 servers.

RoleHostnameIP AddressPurpose
Mastermaster-psql198.51.100.142Primary PostgreSQL Server (read/write)
Slaveslave-psql198.51.100.143Standby PostgreSQL Server (read-only)

Step 1: Install PostgreSQL on Both Servers#

bash
sudo apt update
sudo apt install postgresql postgresql-contrib -y

Verify installation:

bash
psql --version
sudo systemctl status postgresql

Both servers should have PostgreSQL 12.22.


Step 2: Configure the Master Server (198.51.100.142)#

2.1 Edit postgresql.conf#

File path:

text
/etc/postgresql/12/main/postgresql.conf

Uncomment or add the following lines:

text
listen_addresses = '*'
wal_level = replica
max_wal_senders = 5
wal_keep_segments = 64
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/12/main/archive/%f'

Create archive directory:

bash
sudo mkdir -p /var/lib/postgresql/12/main/archive
sudo chown postgres:postgres /var/lib/postgresql/12/main/archive

2.2 Edit pg_hba.conf#

File path:

text
/etc/postgresql/12/main/pg_hba.conf

Add the following line at the end:

text
host    replication     replicator     198.51.100.143/32       md5

2.3 Create a Replication User#

bash
sudo -u postgres psql

Then inside psql:

sql
CREATE ROLE replicator WITH REPLICATION LOGIN ENCRYPTED PASSWORD 'StrongPassword';
\q

2.4 Restart PostgreSQL#

bash
sudo systemctl restart postgresql

Verify configuration:

bash
sudo -u postgres psql -c "show wal_level;"

Expected output:

text
 wal_level
-----------
 replica

Step 3: Configure the Slave Server (198.51.100.143)#

3.1 Stop PostgreSQL#

bash
sudo systemctl stop postgresql

3.2 Remove Existing Cluster Data#

bash
sudo -u postgres rm -rf /var/lib/postgresql/12/main/*

3.3 Take Base Backup from Master#

Run this on the slave:

bash
sudo -u postgres pg_basebackup -h 198.51.100.142 -D /var/lib/postgresql/12/main -U replicator -P -R

Enter the password of user replicator when prompted.

✅ The -R flag automatically:

  • Creates a standby.signal file.
  • Configures replication connection in postgresql.auto.conf.

3.4 Verify Base Backup#

bash
ls /var/lib/postgresql/12/main/

Ensure the file standby.signal exists.


3.5 Start PostgreSQL on Slave#

bash
sudo systemctl start postgresql

Step 4: Verify Replication#

On Master:#

bash
sudo -u postgres psql -c "SELECT client_addr, state, sync_state FROM pg_stat_replication;"

Expected output:

text
 client_addr  |   state   | sync_state
--------------+-----------+------------
 198.51.100.143 | streaming | async
(1 row)

Test Data Replication#

On Master:

bash
sudo -u postgres psql

Then:

sql
CREATE DATABASE testdb;
\c testdb
CREATE TABLE demo(id SERIAL PRIMARY KEY, name TEXT);
INSERT INTO demo(name) VALUES ('hello from master');
\q

On Slave:

bash
sudo -u postgres psql -d testdb -c "SELECT * FROM demo;"

Expected output:

text
 id |       name
----+-------------------
  1 | hello from master
(1 row)

Replication verified ✅


Step 5: Useful Notes#

Hide /root Permission Warning#

Before running sudo -u postgres ...:

bash
cd /tmp

or start a full session as postgres:

bash
sudo -i -u postgres

Promote Slave (Manual Failover)#

If the master fails:

bash
sudo -u postgres pg_ctlcluster 12 main promote

The slave becomes the new master.

Check Replication Status Anytime#

On master:

bash
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"

Final Verification Checklist#

StepDescriptionStatus
PostgreSQL 12 installed on both
Master configured (wal_level, hba, user)
Base backup completed
Slave started with standby.signal
Replication visible on master
Test data synced successfully

Optional (Advanced)#

  • Synchronous replication:

Add to master’s postgresql.conf:

``` synchronous_standby_names = 'slave1'

```

Restart PostgreSQL.

  • Automatic failover:

Use tools like repmgr or pg_auto_failover.


Overview#

This section simulates a real-world database workload on the master to test replication performance and stability.

pgbench is a built-in PostgreSQL tool that generates realistic read/write transactions, mimicking banking or e-commerce workloads.


Step 1: Install pgbench on Master#

bash
sudo apt install postgresql-contrib -y

Step 2: Create the Benchmark Database#

bash
sudo -u postgres createdb pgbenchdb

Step 3: Initialize Sample Schema and Data#

bash
sudo -u postgres pgbench -i -s 10 pgbenchdb

Options explained:

  • i → Initialize tables and load sample data
  • s 10 → Scale factor (creates ~1 million rows total).

Increase to 50 or 100 for heavier load.

This creates 4 default tables:

text
pgbench_accounts
pgbench_branches
pgbench_tellers
pgbench_history

Step 4: Run the Simulation#

Run a 5-minute load test using 10 concurrent clients:

bash
sudo -u postgres pgbench -c 10 -T 300 pgbenchdb

Options explained:

  • c 10 → 10 concurrent clients
  • T 300 → Run for 300 seconds (5 minutes)

Example output:

text
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10
number of clients: 10
number of threads: 10
duration: 300 s
tps = 1550.345 (including connections establishing)

Step 5: Monitor Replication in Real Time (on Master)#

Run this command in another terminal to watch replication lag live:

bash
watch -n 2 "sudo -u postgres psql -c \"SELECT client_addr, state, sync_state, write_lag, flush_lag, replay_lag FROM pg_stat_replication;\""

Example output:

text
 client_addr  |   state   | sync_state | write_lag | flush_lag | replay_lag
--------------+-----------+------------+------------+------------+------------
 198.51.100.143 | streaming | async      | 0 ms       | 0 ms       | 3 ms

If lag values remain small, replication is performing well ✅


Step 6: Verify Data on the Slave#

After the test finishes, confirm data exists on the slave:

bash
sudo -u postgres psql -d pgbenchdb -c "\dt"
sudo -u postgres psql -d pgbenchdb -c "SELECT count(*) FROM pgbench_accounts;"

You should see the same results on both master and slave.


Optional: Heavier Workloads#

Increase intensity:

bash
sudo -u postgres pgbench -c 20 -T 600 -P 10 pgbenchdb

Options:

  • P 10 → Prints progress every 10 seconds
  • Increase c (clients) or T (duration) for more stress testing.

To reinitialize from scratch:

bash
sudo -u postgres dropdb pgbenchdb
sudo -u postgres createdb pgbenchdb
sudo -u postgres pgbench -i -s 20 pgbenchdb

Verification Checklist#

TaskCommandExpected Result
Check replication statusSELECT client_addr, state FROM pg_stat_replication;slave shows “streaming”
Monitor lag in real timewatch -n 2 ...minimal lag (ms range)
Check row counts on both serversSELECT count(*) FROM pgbench_accounts;same results
TPS observed in pgbench outputconsistent value (e.g., 1500 TPS)

Result#

You now have a realistic PostgreSQL workload simulation running on your master, continuously streaming transactions to your slave.

This confirms replication reliability under real operational load