Connecting clients (primary-following, no proxy)

pg_replica needs no router or VIP in front of it. Every node is an endpoint; the client is handed all of them and finds the primary itself — exactly like a MongoDB mongodb://h1,h2,h3/?replicaSet=... connection string.

Why it just works

A target_session_attrs=read-write client decides “is this the primary?” by running SHOW transaction_read_only on each host and keeping the one that returns off. pg_replica’s fence already sets that for us:

node state transaction_read_only client verdict
authorized primary off connect here
standby (in recovery) on skip
fenced ex-primary / lost-quorum minority on skip

So the client lands on the current authorized primary, and during a failover or a loss-of-quorum window it finds no read-write host and fails fast — the app retries, and there is never a write to a fenced node (no split-brain). On failover the only thing the application does is reconnect.

The connection string (libpq keyword form):

host=10.0.0.1,10.0.0.2,10.0.0.3 port=5432 user=app dbname=weido target_session_attrs=read-write connect_timeout=2

Rust — tokio-postgres (verified, see scripts/test-m6-routing.sh)

use std::str::FromStr;
use tokio_postgres::{Config, NoTls};

let config = Config::from_str(
    "host=10.0.0.1,10.0.0.2,10.0.0.3 port=5432 \
     user=app dbname=weido target_session_attrs=read-write connect_timeout=2",
)?;
let (client, connection) = config.connect(NoTls).await?; // lands on the primary

On a failed query after a failover, drop the client and call connect again — it re-scans and lands on the new primary.

  1. connection pool: https://github.com/djc/bb8 / https://github.com/fboulnois/nanopool

psql / libpq / any libpq-based driver (psycopg, JDBC via pgjdbc, etc.)

psql "host=10.0.0.1,10.0.0.2,10.0.0.3 port=5432 user=app dbname=weido target_session_attrs=read-write"

Read scaling (optional)

target_session_attrs=read-only (or prefer-standby on PG 14+) routes a connection to a standby instead — useful for read-heavy / ParadeDB search queries that can tolerate replication lag. Use a separate read-only pool for those.