How to fix FATAL: database system identifier differs between primary and standby in PostgreSQL

PostgreSQLADVANCEDHIGHUpdated Dec 26, 2025· 186 views

This replication error occurs when a standby PostgreSQL server's database system identifier doesn't match the primary server's identifier, indicating they are not properly related. This happens when the standby wasn't created from a backup of the primary.

Quick fix

Fixes FATAL: database system identifier differs between primary and standby

sudo systemctl stop postgresql
# or for a specific version
sudo systemctl stop postgresql@15-main
  1. Stop the standby PostgreSQL server
  2. Backup and remove the incorrect standby data directory
  3. Create a fresh base backup from the primary using pg_basebackup
  4. Verify the standby configuration files
postgresql — error
sudo systemctl stop postgresql
# or for a specific version
sudo systemctl stop postgresql@15-main
FATAL: database system identifier differs between primary and standby

What this error means

PostgreSQL's database system identifier is a unique identifier assigned to each database cluster at initialization time. During physical replication setup, the standby server must be an exact binary copy of the primary to maintain data consistency. When this error occurs, it means you're trying to set up replication between two unrelated database clusters—the standby is either from a different PostgreSQL instance entirely or was not properly cloned from the primary. The error typically includes a DETAIL line showing both identifiers: "The primary's identifier is XXXXXXX, the standby's identifier is YYYYYYY." These numbers will be different if the standby wasn't created from the primary's backup.

Typical symptoms

  • Standby server fails to start with FATAL error in logs
  • Replication connection attempt fails immediately
  • pg_basebackup was not used to initialize the standby
  • You have multiple PostgreSQL instances on the standby machine and started the wrong one
  • Standby connects briefly then disconnects with system identifier mismatch

Common causes

  1. Standby database was not created from a backup of the primary (most common)
  2. Wrong PostgreSQL data directory is being used on the standby (multiple instances)
  3. Standby data directory is from a different PostgreSQL cluster entirely
  4. pg_basebackup was used incorrectly or with the wrong source server
  5. PITR (Point-in-Time Recovery) backup wasn't used for standby initialization
  6. Manual data directory copy without using pg_basebackup

How to fix "FATAL: database system identifier differs between primary and standby"

1Stop the standby PostgreSQL server

First, ensure the standby server is completely stopped to prevent data corruption:

bash
sudo systemctl stop postgresql
# or for a specific version
sudo systemctl stop postgresql@15-main

Verify it's stopped:

bash
sudo systemctl status postgresql
2Backup and remove the incorrect standby data directory

Before removing, back up the current data directory in case you need to investigate:

bash
# Backup the existing standby data
sudo mv /var/lib/postgresql/15/main /var/lib/postgresql/15/main.bak

# Or if using a different version/path:
sudo mv /path/to/postgres/data /path/to/postgres/data.bak

Then create a fresh, empty directory with correct permissions:

bash
sudo mkdir -p /var/lib/postgresql/15/main
sudo chown postgres:postgres /var/lib/postgresql/15/main
sudo chmod 700 /var/lib/postgresql/15/main
3Create a fresh base backup from the primary using pg_basebackup

This is the critical step. Run pg_basebackup on the standby to copy the entire database cluster from the primary:

bash
sudo -u postgres pg_basebackup \
  -h <primary_ip_or_hostname> \
  -p 5432 \
  -U replication \
  -D /var/lib/postgresql/15/main \
  -Fp \
  -Xs \
  -R

Flag explanations:
- -h: IP or hostname of the primary server
- -p: PostgreSQL port on the primary (default 5432)
- -U replication: User with replication privileges (must exist on primary)
- -D: Destination data directory on standby
- -Fp: Plain format (not tar)
- -Xs: Stream WAL (Write-Ahead Logs) while backup runs
- -R: Automatically create standby.signal and postgresql.auto.conf

Example:

bash
sudo -u postgres pg_basebackup \
  -h 192.168.1.10 \
  -p 5432 \
  -U replication \
  -D /var/lib/postgresql/15/main \
  -Fp \
  -Xs \
  -R

This process may take several minutes depending on database size. Wait for it to complete.

4Verify the standby configuration files

After pg_basebackup completes, verify the standby configuration files were created correctly:

bash
# Check standby.signal exists (indicates standby mode)
sudo ls -la /var/lib/postgresql/15/main/standby.signal

# Check postgresql.auto.conf was created
sudo cat /var/lib/postgresql/15/main/postgresql.auto.conf

The postgresql.auto.conf should contain lines like:

bash
primary_conninfo = 'host=192.168.1.10 port=5432 user=replication password=...'

If these files don't exist, the pg_basebackup likely failed. Check the output above for error messages.

5Start the standby server

Now start PostgreSQL with the correct data:

bash
sudo systemctl start postgresql
# or for specific version
sudo systemctl start postgresql@15-main

Check the status:

bash
sudo systemctl status postgresql

Check the logs for any errors:

bash
sudo tail -f /var/log/postgresql/postgresql-15-main.log

You should see messages like:

bash
LOG: database system was interrupted while in recovery at log time 2024-01-15 10:30:45 UTC
LOG: entering standby mode
LOG: started streaming WAL from primary at 0/3000000 on timeline 1
6Verify replication is working

Connect to the primary server and check replication status:

bash
# On primary
psql -U postgres

Then run:

sql
SELECT slot_name, slot_type, active FROM pg_replication_slots;
SELECT pid, usename, application_name, client_addr, state FROM pg_stat_replication;

You should see the standby listed as an active replication connection. Example output:

bash
pid   | usename |  application_name  | client_addr  | state
---------+---------+--------------------+--------------+----------
  12345  | replication | walreceiver | 192.168.1.20 | streaming

If the standby is not listed, check the primary logs and standby logs for connection errors.

Advanced notes

Replication User Setup: The user specified with -U must have REPLICATION privilege on the primary. Create it with:

sql
CREATE ROLE replication WITH LOGIN REPLICATION;
ALTER ROLE replication WITH PASSWORD 'secure_password';

Then add to primary's pg_hba.conf:

bash
host    replication     replication     192.168.1.20/32     md5

Synchronous Replication: For high-availability setups, configure synchronous_commit on the primary to wait for standby acknowledgment before committing transactions. This adds latency but ensures zero data loss.

WAL Archive Strategy: For production replication, configure WAL archiving on the primary to handle WAL files that arrive after the backup completes. Without this, the standby might fall behind if the primary has high write volume.

Network Issues: If pg_basebackup fails with connection refused, verify the primary's listen_addresses includes the standby IP and pg_hba.conf allows replication connections from the standby.

Large Databases: For databases over 100GB, pg_basebackup may take a long time. Monitor the primary's CPU and disk I/O during backup. Use -j flag for parallel backup on PostgreSQL 10+:

bash
pg_basebackup -h primary -U replication -D /var/lib/postgresql/15/main -j 4

Failover Considerations: Once replication is confirmed working, plan your failover procedure using tools like pg_ctl promote (manual) or replication manager extensions like repmgr for automated failover.

Frequently asked questions

What does "FATAL: database system identifier differs between primary and standby" mean?
PostgreSQL's database system identifier is a unique identifier assigned to each database cluster at initialization time. During physical replication setup, the standby server must be an exact binary copy of the primary to maintain data consistency. When this error occurs, it means you're trying to set up replication between two unrelated database clusters—the standby is either from a different PostgreSQL instance entirely or was not properly cloned from the primary.
How do I fix "FATAL: database system identifier differs between primary and standby"?
This replication error occurs when a standby PostgreSQL server's database system identifier doesn't match the primary server's identifier, indicating they are not properly related. This happens when the standby wasn't created from a backup of the primary.
What causes "FATAL: database system identifier differs between primary and standby"?
Standby database was not created from a backup of the primary (most common) Wrong PostgreSQL data directory is being used on the standby (multiple instances) Standby data directory is from a different PostgreSQL cluster entirely
Is the "FATAL: database system identifier differs between primary and standby" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading