PgDoorman vs PgBouncer vs Odyssey

Side-by-side feature matrix for choosing a PostgreSQL connection pooler. Every PgBouncer claim is anchored to its config reference and changelog; every Odyssey claim is anchored to the project's docs.

PgCat is intentionally omitted: its design centre is sharding/load-balancing rather than drop-in replacement of PgBouncer, so a row-by-row comparison is misleading. See the PgCat repo if you need horizontal sharding.

For benchmark numbers, see Benchmarks.

Authentication

FeaturePgDoormanPgBouncerOdyssey
MD5 passwordYesYesYes
SCRAM-SHA-256 (client → pooler)YesYesYes
SCRAM-SHA-256 passthrough (no plaintext password in config)Yes (ClientKey extracted from client proof)Yes (since 1.14, encrypted SCRAM secret in auth_query / userlist.txt)Yes
MD5 passthroughYesYesYes
auth_query (dynamic users)YesYesYes
auth_query passthrough mode (per-user backend identity)YesNo (single auth_user for all lookups)Yes
pg_hba.conf-style fileYes (file or inline)Yes (auth_hba_file)Yes (since 1.4)
PAMYes (Linux)Yes (auth_type=pam or via HBA)Yes
JWT (RSA-SHA256)YesNoNo
Talos (custom JWT with role extraction)Yes (Ozon-specific)NoNo
LDAPNoYes (since 1.25)Yes
SCRAM channel binding (scram-sha-256-plus)NoYesYes
User-name maps (cert/peer → DB user)NoYes (since 1.23)Yes
Tunable scram_iterationsNoYes (since 1.25)No

See Authentication.

TLS

FeaturePgDoormanPgBouncerOdyssey
Client-side TLS (modes: disable, allow, require, verify-full)YesYes (disable, allow, prefer, require, verify-ca, verify-full)Yes
Server-side TLS to PostgreSQL (disable, allow, require, verify-ca, verify-full)Yes (5 modes)Yes (server_tls_*, 6 modes incl. prefer)No
mTLS to PostgreSQL (client cert sent to backend)Yes (server_tls_certificate + server_tls_private_key)Yes (server_tls_key_file + server_tls_cert_file)No
Hot reload of server-side TLS certificatesYes (SIGHUP)Yes (via RELOAD / SIGHUP, "new file contents will be used for new connections")No
Hot reload of client-facing TLS certificatesNo (SIGHUP unsupported; handoff loads new files for new connections only)Yes (via RELOAD / SIGHUP)No
Minimum TLS version configurableYes (defaults to TLS 1.2)Yes (tls_protocols, default tlsv1.2,tlsv1.3)Configurable, defaults differ
Direct TLS handshake (PostgreSQL 17, no SSLRequest)NoYes (since 1.25)No
TLS 1.3 cipher controlNoYes (since 1.25, client_tls13_ciphers/server_tls13_ciphers)No
TLS session migration across binary upgradeYes (Linux tls-migration build, same cert/key)No (TLS connections are dropped during online restart)No

See TLS.

Routing and high availability

FeaturePgDoormanPgBouncerOdyssey
Patroni-assisted fallback (built-in /cluster lookup)YesNoNo
Bundled TCP proxy with role-based routing (patroni_proxy)YesNoNo
Replica lag guardYes (max_lag_in_bytes in patroni_proxy)NoYes (watchdog_lag_query + catchup_timeout)
Multiple backend hosts with load balancingYes (patroni_proxy)Yes (since 1.24, load_balance_hosts)Yes
target_session_attrs (read-write / read-only routing)Yes (via patroni_proxy roles)NoYes
Sequential routing rules (first-match wins)NoNoYes
Connection-type routing (TCP vs UNIX)NoNoYes
Availability-zone-aware host selectionNoNoYes

See Patroni-assisted fallback, patroni_proxy.

Pooling

FeaturePgDoormanPgBouncerOdyssey
Pool modessession, transactionsession, transaction, statementsession, transaction
Pool Coordinator (per-database cap with priority eviction)Yes (max_db_connections + p95-ranked eviction)No (max_db_connections queues clients until idle timeout closes existing connections)No
Reserve poolYes (reserve_pool_size)Yes (reserve_pool_size)No
Per-user min_guaranteed_pool_sizeYesNoNo
Pre-replacement on server_lifetime expiry (warm before old expires)Yes (95% threshold, up to 3 in parallel)NoNo
Anticipation / burst scaling (scaling_warm_pool_ratio, fast retries)YesNoNo
Direct-handoff (returning server goes to longest-waiting client via in-process oneshot channel)YesNoNo
Strict FIFO ordering of waitersYesNo (LIFO via server_round_robin = 0)No
min_pool_size (warm connections)YesNoYes
Prepared statements in transaction modeYes (named and anonymous, two-level cache, query interner)Yes (named, since 1.21, max_prepared_statements)Yes (named, pool_reserve_prepared_statement)
Anonymous Parse cache for performanceYes (DOORMAN_N, reused across clients in a pool)No (anonymous Parse passes through unchanged)No (named statements required)
Smart cleanup on checkin (skip DEALLOCATE ALL if cache untouched)Yes (mutation-tracking RESET ALL / DEALLOCATE ALL on demand)No (always DISCARD ALL if server_reset_query set)Yes (auto)
LISTEN / NOTIFY pinning in transaction modeNoNoExperimental
Cross-rule connection cap (shared_pool)NoNoYes (since 1.5.1)
PAUSE / RESUME / RECONNECT admin commandsYesYesYes (since 1.4.1)
Configured PostgreSQL GUCs in backend StartupMessage per poolYes (startup_parameters, applied as general → pool → passthrough auth_query; client RESET ALL / DISCARD ALL returns to those values; PG startup errors reach the client unchanged)No equivalent configured defaults; selected client startup parameters can be tracked or ignoredNo (maintain_params preserves client-side parameters across rebind; no configured GUCs)

See Pool Coordinator, Pool pressure.

Limits and timeouts

FeaturePgDoormanPgBouncerOdyssey
server_idle_check_timeout (probe before checkout)YesNoNo
idle_timeout (server-side)Yes (idle_timeout)Yes (server_idle_timeout)Yes
server_lifetimeYesYesYes
query_wait_timeoutYesYesYes
client_idle_timeoutNoYes (since 1.24)No
transaction_timeout (pooler-enforced)NoYes (since 1.25)No
max_user_client_connectionsNoYes (since 1.24)No
max_db_client_connectionsNoYes (since 1.24)No
Per-user query_timeoutNoYes (since 1.24)No
Per-user reserve_pool_sizeNoYes (since 1.24)No
Notify client while waiting for backendNoYes (since 1.25, query_wait_notify)Yes (pool_notice_after_waiting_ms)

See General settings reference, Pool settings reference.

Observability

FeaturePgDoormanPgBouncerOdyssey
Built-in admin web UI (HTML console in the binary)Yes (single-page console on the same port as /metrics, opt-in via [web].ui)No (psql admin console only)No (psql admin console only)
Prometheus endpointBuilt-in /metricsExternal (pgbouncer_exporter)External (Go exporter sidecar that polls the admin console)
Latency percentiles per pool (p50, p90, p95, p99)Yes (HDR Histogram)No (averages only in SHOW STATS)Yes via the exporter (TDigest, requires quantiles rule option)
Prepared statement counters in SHOW STATSYesYes (since 1.24)No
JSON structured loggingYes (--log-format structured)NoYes (log_format "json")
Runtime log level control (SET log_level)YesNoNo
SHOW POOL_COORDINATOR / SHOW POOL_SCALING / SHOW SOCKETSYesNoNo
SHOW PREPARED_STATEMENTSYesNoNo
SHOW INTERNER (per-kind entries / bytes / preview)YesNoNo
Bounded prepared-statement cache (TTL on anonymous, per-client LRU split)YesNamed only, bounded by max_prepared_statements; no anonymous cacheNo
SHOW HOSTS (host CPU/memory)NoNoYes
SHOW RULES (dump effective routing)NoNoYes
Server-side TLS connection metrics (handshake duration, errors, active count)YesNoNo
Patroni API metricsYesNoNo
Fallback metrics (active flag, current host, hits)YesNoNo

See Prometheus metrics reference, Admin commands.

Operations

FeaturePgDoormanPgBouncerOdyssey
Binary upgrade with session migration (TCP socket, cancel keys, prepared cache)Yes (SCM_RIGHTS, plus TLS state with Linux tls-migration and same cert/key)No: -R deprecated since 1.20; so_reuseport rolling restart drains old sessions in placeNo: SIGUSR2 + bindwith_reuseport drains old sessions in place
Configuration formatYAML or TOMLINIOwn format (lex/yacc)
Human-readable durations and sizes (30s, 1h, 256MB)YesNo (integer microseconds / bytes)No
Config test mode (pg_doorman -t)YesNoNo
Auto-config from PostgreSQL (pg_doorman generate --host)YesNoNo
SIGHUP reloadYes (server TLS certs included; client TLS still requires restart)Yes (auth_file, auth_hba_file, server and client TLS certs)Yes
systemd sd-notify (Type=notify) integrationYesNoNo
Memory cap (max_memory_usage)YesNoNo
TCP socket buffer capYes (tcp_socket_buffer_size, client and backend TCP sockets)Yes (tcp_socket_buffer)No

See Binary upgrade, Signals.

Protocol

FeaturePgDoormanPgBouncerOdyssey
Simple queryYesYesYes
Extended queryYesYesPartial
Pipelined batchesYesYesPartial
Async FlushYesYesNo
Cancel requests over TLSYesYesYes
COPY IN / COPY OUTYesYesYes
Replication passthrough (replication=true startup)NoYes (since 1.23)No
Protocol version negotiation (3.2)NoYes (since 1.23)No
server_drop_on_cached_plan_errorNoNoYes (since 1.5.1)

When PgDoorman is not the right fit

  • You need LDAP authentication. Use Odyssey or PgBouncer 1.25+.
  • You need replication passthrough for logical replication tools. Use PgBouncer 1.23+.
  • You need transaction_timeout enforced by the pooler. Use PgBouncer 1.25+.
  • You need horizontal sharding inside the pooler. Use PgCat.

For prepared statements in transaction mode, Patroni HA without external proxies, multi-threaded throughput in a single shared pool, and binary upgrades that migrate live sessions, PgDoorman is the closer fit.