Settings

Configuration File Format

pg_doorman supports two configuration file formats:

  • YAML (.yaml, .yml) - The primary and recommended format for new configurations.
  • TOML (.toml) - Supported for backward compatibility with existing configurations.

The format is automatically detected based on the file extension. Both formats support the same configuration options and can be used interchangeably.

general:
  host: "0.0.0.0"
  port: 6432
  admin_username: "admin"
  admin_password: "change_me_to_a_long_random_secret"

pools:
  mydb:
    server_host: "localhost"
    server_port: 5432
    pool_mode: "transaction"
    users:
      - username: "myuser"
        password: "md5..."  # hash from pg_shadow / pg_authid
        pool_size: 40

Example TOML Configuration (Legacy)

[general]
host = "0.0.0.0"
port = 6432
admin_username = "admin"
admin_password = "change_me_to_a_long_random_secret"

[pools.mydb]
server_host = "localhost"
server_port = 5432
pool_mode = "transaction"

[[pools.mydb.users]]
username = "myuser"
password = "md5..."  # hash from pg_shadow / pg_authid
pool_size = 40

Generate Command

The generate command can output configuration in either format. The format is determined by the output file extension. By default, the generated config includes detailed inline comments explaining every parameter.

# Generate YAML configuration (recommended)
pg_doorman generate --output config.yaml

# Generate TOML configuration (for backward compatibility)
pg_doorman generate --output config.toml

# Generate a complete reference config without PG connection
pg_doorman generate --reference --output config.yaml

# Generate reference config with Russian comments
pg_doorman generate --reference --ru --output config.yaml

# Generate config without comments (plain serialization)
pg_doorman generate --no-comments --output config.yaml
FlagDescription
--no-commentsDisable inline comments in generated config (by default, comments are included)
--referenceGenerate a complete reference config with example values, no PostgreSQL connection needed
--russian-comments, --ruGenerate comments in Russian for quick start guide
--format, -fOutput format: yaml (default) or toml. If --output is specified, format is auto-detected from file extension. This flag overrides auto-detection

Include Files

Include files can be in either format, and you can mix formats. For example, a YAML main config can include TOML files and vice versa:

include:
  files:
    - "pools.yaml"
    - "users.toml"

Human-Readable Values

pg_doorman supports human-readable formats for duration and byte size values, while maintaining backward compatibility with numeric values.

Duration Format

Duration values can be specified as:

  • Plain numbers: interpreted as milliseconds (e.g., 5000 = 5 seconds)
  • String with suffix:
    • ms - milliseconds (e.g., "100ms")
    • s - seconds (e.g., "5s" = 5000 milliseconds)
    • m - minutes (e.g., "5m" = 300000 milliseconds)
    • h - hours (e.g., "1h" = 3600000 milliseconds)
    • d - days (e.g., "1d" = 86400000 milliseconds)

Examples:

general:
  # All these are equivalent (3 seconds):
  # connect_timeout: 3000      # backward compatible (milliseconds)
  # connect_timeout: "3s"      # human-readable
  # connect_timeout: "3000ms"  # explicit milliseconds
  connect_timeout: "3s"
  idle_timeout: "10m"        # 10 minutes
  server_lifetime: "1h"      # 1 hour

Byte Size Format

Byte size values can be specified as:

  • Plain numbers: interpreted as bytes (e.g., 1048576 = 1 MB)
  • String with suffix (case-insensitive):
    • B - bytes (e.g., "1024B")
    • K or KB - kilobytes (e.g., "1K" or "1KB" = 1024 bytes)
    • M or MB - megabytes (e.g., "1M" or "1MB" = 1048576 bytes)
    • G or GB - gigabytes (e.g., "1G" or "1GB" = 1073741824 bytes)

Note: Uses binary prefixes (1 KB = 1024 bytes, not 1000 bytes).

Examples:

general:
  # All these are equivalent (256 MB):
  # max_memory_usage: 268435456  # backward compatible (bytes)
  # max_memory_usage: "256MB"    # human-readable
  # max_memory_usage: "256M"     # short form
  max_memory_usage: "256MB"
  unix_socket_buffer_size: "1MB" # 1 MB
  worker_stack_size: "8MB"       # 8 MB

General Settings

host

Listen host (TCP v4 only).

Default: "0.0.0.0".

port

Listen port for incoming connections.

Default: 5432.

backlog

TCP backlog for incoming connections. A value of zero sets the max_connections as value for the TCP backlog.

Default: 0.

max_connections

The maximum number of clients that can connect to the pooler simultaneously. When this limit is reached:

  • A client connecting without SSL will receive the expected error (code: 53300, message: sorry, too many clients already).
  • A client connecting via SSL will see a message indicating that the server does not support the SSL protocol.

Default: 8192.

max_concurrent_creates

Maximum number of server connections that can be created concurrently per pool. This setting uses a semaphore to limit parallel connection creation, which significantly improves performance during cold start and burst scenarios.

Higher values allow faster pool warm-up but may increase load on the PostgreSQL server during connection storms. Lower values provide more gradual connection creation.

Default: 4.

tls_mode

The TLS mode for incoming connections. It can be one of the following:

  • allow - TLS connections are allowed but not required. The pg_doorman will attempt to establish a TLS connection if the client requests it.
  • disable - TLS connections are not allowed. All connections will be established without TLS encryption.
  • require - TLS connections are required. The pg_doorman will only accept connections that use TLS encryption.
  • verify-full - TLS connections are required and the pg_doorman will verify the client certificate. This mode provides the highest level of security.

Default: "allow".

tls_ca_cert

CA certificate file used to verify client certificates. Required when tls_mode is set to verify-full.

Default: None.

tls_private_key

Path to the private key file for TLS connections. Required to enable TLS for incoming client connections. Must be used together with tls_certificate.

Default: None.

tls_certificate

Path to the certificate file for TLS connections. Required to enable TLS for incoming client connections. Must be used together with tls_private_key.

Default: None.

tls_rate_limit_per_second

Limit the number of simultaneous attempts to create a TLS session. Any value other than zero implies that there is a queue through which clients must pass in order to establish a TLS connection. In some cases, this is necessary in order to launch an application that opens many connections at startup (the so-called "hot start").

Default: 0.

daemon_pid_file

Enabling this setting enables daemon mode. Comment this out if you want to run pg_doorman in the foreground with -d.

Default: "/tmp/pg_doorman.pid".

syslog_prog_name

When specified, pg_doorman starts sending messages to syslog (using /dev/log or /var/run/syslog). Comment this out if you want to log to stdout.

Default: None.

log_client_connections

Log client connections for monitoring.

Default: true.

log_client_disconnections

Log client disconnections for monitoring.

Default: true.

worker_threads

Number of Tokio runtime worker threads (OS threads) for serving client connections. Performance scales linearly up to the number of CPU cores. Also determines the shard count for internal concurrent hash maps (worker_threads * 4, rounded to nearest power of 2, minimum 4). In Kubernetes, set this explicitly — automatic CPU detection may report the host's cores instead of the container's limit.

Default: 4.

worker_cpu_affinity_pinning

Bind each worker thread to a separate CPU core (sched_setaffinity). Disabled when fewer than 3 cores are available.

Default: false.

tokio_global_queue_interval

Tokio runtime settings. Controls how often the scheduler checks the global task queue. Modern tokio versions handle this well by default, so this parameter is optional.

Default: not set (uses tokio's default).

tokio_event_interval

Tokio runtime settings. Controls how often the scheduler checks for external events (I/O, timers). Modern tokio versions handle this well by default, so this parameter is optional.

Default: not set (uses tokio's default).

worker_stack_size

Tokio runtime settings. Sets the stack size for worker threads. Modern tokio versions handle this well by default, so this parameter is optional.

Default: not set (uses tokio's default).

max_blocking_threads

Tokio runtime settings. Sets the maximum number of threads for blocking operations. Modern tokio versions handle this well by default, so this parameter is optional.

Default: not set (uses tokio's default).

connect_timeout

Maximum time to wait when establishing a new connection to a PostgreSQL server. If the connection cannot be established within this period, the attempt is aborted. Similar to PgBouncer's server_connect_timeout.

Default: 3000 (3 sec).

query_wait_timeout

Maximum time a client query can wait for a server connection when the pool is fully utilized. If no server connection becomes available within this period, the client receives an error. Similar to PgBouncer's query_wait_timeout.

Default: 5000 (5 sec).

idle_timeout

Close a server connection that has been idle (not checked out by any client) longer than this value. Only applies to connections that have served at least one client request. Prewarmed or replenished connections that were never checked out are not subject to idle_timeout — they are only closed when server_lifetime expires. Each connection gets ±20% jitter to prevent synchronized mass closures. Set to 0 to disable. Similar to PgBouncer's server_idle_timeout.

Default: 600000 (10 min).

server_lifetime

Maximum age of a server connection. When a connection exceeds this age and becomes idle, it is closed during the next retain cycle. Active transactions are not interrupted. Applies to all connections, including prewarmed ones that were never checked out by a client. Each connection gets ±20% jitter to prevent thundering herd. Set to 0 to disable. Similar to PgBouncer's server_lifetime.

Default: 1200000 (20 min).

retain_connections_time

Interval for checking and closing idle connections that exceed idle_timeout or server_lifetime. The retain task runs periodically at this interval to clean up expired connections.

Default: 30000 (30 sec).

retain_connections_max

Maximum number of idle connections to close per retain cycle. When set to 0, all idle connections that exceed idle_timeout or server_lifetime will be closed immediately. When set to a positive value, at most that many connections will be closed per cycle across all pools.

This parameter controls how aggressively pg_doorman closes idle connections. With the default value of 3, up to 3 connections are closed per retain cycle, providing controlled cleanup. If you need faster cleanup of expired connections, set to 0 (unlimited) to close all expired connections in each retain cycle.

Default: 3.

server_idle_check_timeout

Time after which an idle server connection should be checked before being given to a client. This helps detect dead connections caused by PostgreSQL restart, network issues, or server-side idle timeouts.

When a connection has been idle in the pool longer than this timeout, pg_doorman will send a minimal query (;) to verify the connection is still alive before returning it to the client. If the check fails, the connection is discarded and a new one is obtained.

Set to 0 to disable the check (not recommended for production environments with potential network instability or PostgreSQL restarts).

Default: 60s (60 seconds).

server_round_robin

Controls which idle server connection is picked for the next transaction. false (LRU): reuses the most recently returned connection. Keeps fewer connections hot, better for PostgreSQL shared buffer locality. true (Round Robin): rotates across all idle connections evenly. Similar to PgBouncer's server_round_robin.

Default: false.

sync_server_parameters

In transaction mode, different transactions from the same client may run on different backend connections. With sync_server_parameters = true, pg_doorman applies the client's session parameters to the selected backend before the transaction starts.

Values come from two places:

  1. PostgreSQL ParameterStatus messages: client_encoding, DateStyle, IntervalStyle, TimeZone, standard_conforming_strings, application_name. PostgreSQL reports changes to these parameters over the protocol.

  2. Safe client StartupMessage parameters (new in pg_doorman 3.10): any parameter sent by the client during connection startup, except server-managed or read-only names (is_superuser, server_version, lc_collate, transaction_isolation, ...) and the protocol-reserved _pq_. prefix. This lets clients set search_path, default_transaction_isolation, role, and similar planner inputs once at connection time. Configured startup_parameters always override the client packet.

Important limits:

  • pg_doorman tracks startup parameters and PostgreSQL-reported parameters only. If a client runs SET search_path = ... or changes another unreported planner GUC after connection startup, pg_doorman does not see that change. Later prepared-statement reuse can then use a plan built under older planner state. Clients that need runtime planner-GUC changes should set those values in StartupMessage, run DISCARD ALL or reconnect after changing them, or disable prepared_statements for the pool.

  • The prepared-statement cache key includes the query text, parameter OIDs, and a digest of these startup-time planner GUCs: search_path, default_transaction_isolation, default_transaction_read_only, default_text_search_config, role. Other planner inputs (TimeZone, DateStyle, plan_cache_mode, enable_*, JIT cost knobs, extension GUCs) are not part of the key. If the same prepared query runs under different values of those parameters, disable prepared_statements for the pool or pin the parameters at the role/database level.

Adds one extra SET/RESET round trip only when the backend state differs from the client state. If you only need application_name visibility in pg_stat_activity, use the pool-level application_name setting instead.

Default: false.

tcp_so_linger

By default, pg_doorman send RST instead of keeping the connection open for a long time.

Default: 0.

tcp_no_delay

TCP_NODELAY to disable Nagle's algorithm for lower latency.

Default: true.

tcp_keepalives_count

Number of unacknowledged TCP keepalive probes before the connection is considered dead and closed.

Default: 5.

tcp_keepalives_idle

Keepalive enabled by default and overwrite OS defaults.

Default: 5.

tcp_keepalives_interval

Interval in seconds between individual TCP keepalive probes after the initial idle period (tcp_keepalives_idle) has passed.

Default: 5.

tcp_user_timeout

Sets the TCP_USER_TIMEOUT socket option for client connections (in seconds). This option specifies the maximum time that transmitted data may remain unacknowledged before TCP will forcibly close the connection. This helps detect dead client connections faster than keepalive probes when the connection is actively sending data but the remote end has become unreachable (e.g., network failure, client crash).

When set to a non-zero value, if data remains unacknowledged for this duration, the connection will be terminated. Use it to avoid 15-16 minute delays caused by TCP retransmission timeout when keepalive cannot help (e.g., during active data transmission).

Note: This option is only supported on Linux. On other operating systems, this setting is ignored.

Set to 0 to disable (use OS default).

Default: 60.

tcp_socket_buffer_size

Kernel SO_RCVBUF/SO_SNDBUF limits for accepted client TCP sockets, accepted web TCP sockets, and outbound backend TCP sockets.

With the default 0, pg_doorman does not call setsockopt(SO_RCVBUF/SO_SNDBUF) and Linux TCP autotuning stays in charge. Per-connection receive buffers can grow on demand up to net.ipv4.tcp_rmem[2] (commonly 6 MiB on Ubuntu/RHEL). That memory is not process RSS; depending on kernel and cgroup mode it may appear separately as socket memory, for example as sock in cgroup v2 memory.stat, or mostly as host-level kernel memory. If MemFree jumps after a pg_doorman restart, confirm the source with ss -m, /proc/net/sockstat, cgroup v2 memory.current, and memory.stat key sock.

Setting a non-zero value calls setsockopt(SO_RCVBUF/SO_SNDBUF) once per configured TCP socket. This disables autotuning for that socket and sets fixed send/receive buffer limits. Linux internally doubles the requested values — see man 7 socket — and may clamp them by net.core.rmem_max / net.core.wmem_max. Check /proc/sys/net/core/rmem_max and /proc/sys/net/core/wmem_max before choosing values above the OS default. getsockopt, ss -m, and pg_doorman DEBUG logs show the kernel-applied values.

The rough Linux limit is 4 * tcp_socket_buffer_size * tcp_socket_count: send and receive buffers are both configured, and Linux doubles each requested value internally. For example, tcp_socket_buffer_size = 65536 sets about 256 KiB of send+receive limits per TCP socket, so 60 TCP sockets have about 15 MiB of configured kernel buffer limits before sk_buff overhead. Count client TCP sockets, web TCP sockets, and backend TCP sockets. Actual resident memory still depends on queued data.

This setting is primarily a memory cap. Suggested starting range for OLTP traffic inside one datacenter: 64 KiB – 256 KiB. Do not set less than 64 KiB unless measurements show it is safe. WAN links, cross-zone traffic, large result sets, and bulk transfers may need a larger value or the default autotuning behaviour.

The value is applied when pg_doorman configures a TCP socket: on accepted client sockets, accepted web sockets, outbound backend sockets, and migrated client sockets reconstructed during binary upgrade. SIGHUP reload does not revisit already-open sockets. To apply a new value to existing sessions, use binary upgrade for migrated clients, reconnect/drain pools for backend sockets, or restart when reconnects are acceptable.

Equivalent of PgBouncer's tcp_socket_buffer parameter. Odyssey and PgCat have no analogue and inherit the kernel autotuner's behaviour.

Default: 0.

unix_socket_buffer_size

Buffer size for read and write operations when connecting to PostgreSQL via a unix socket.

Default: 1048576.

unix_socket_dir

Directory for Unix domain socket listener. Creates .s.PGSQL. socket file for local client connections.

Default: null.

unix_socket_mode

Permission mode applied to the Unix domain socket file .s.PGSQL.<port> immediately after bind(). Specified as an octal string (e.g. "0600", "0660", "0666"). Only the lowest 9 bits are honored — setuid/setgid/sticky bits are rejected.

The default "0600" restricts socket access to the user running pg_doorman. To let other local users connect, set a more permissive mode such as "0660" (group access) or "0666" (any local user). When loosening the mode, ensure the parent directory permissions allow traversal by the intended group.

Default: "0600".

admin_username

Access to the virtual admin database is carried out through the administrator's username and password.

Default: "admin".

admin_password

Access to the virtual admin database is carried out through the administrator's username and password. It should be replaced with your secret.

Default: "admin".

prepared_statements

Enables prepared-statement remapping and caching. When disabled, pg_doorman forwards Parse and Bind without rewriting them through the pool-level prepared-statement cache.

If this is true, prepared_statements_cache_size must be greater than 0.

Default: true.

prepared_statements_cache_size

Cache size of prepared statements at the pool level (shared across all clients connecting to the same pool). This cache stores the mapping from query hash to rewritten prepared statement name.

This is not the disable switch. To disable prepared-statement remapping, set prepared_statements: false; pg_doorman rejects a general prepared_statements_cache_size of 0 while prepared_statements is enabled.

For an end-to-end picture of how this knob interacts with server_prepared_statements_cache_size, client_anonymous_prepared_cache_size, and the query interner, see the Anonymous Parse caching tutorial.

Default: 8192.

server_prepared_statements_cache_size

Sizes the per-backend LruCache<String, ()> of DOORMAN_<N> names independently of the pool-level cache. When unset (default), inherits the resolved prepared_statements_cache_size for that pool. A per-pool override on this field takes precedence over this general value.

Lower this knob below the pool size when backends carry too many DOORMAN_<N> rows (pg_prepared_statements near the cap, plan memory ballooning) or when faster Close recycling is desired without shrinking pool-level hit rate. Forced to 0 when prepared_statements: false.

Default: not set (inherits prepared_statements_cache_size).

client_anonymous_prepared_cache_size

Bounds the Anonymous part of the per-client prepared-statement cache. Anonymous statements are issued without an explicit name and are typically short-lived; the LRU caps how many of them a single client can accumulate before the oldest one is evicted.

When unset (default), inherits the resolved prepared_statements_cache_size for the pool. Set to 0 to disable the LRU and fall back to an unlimited map for Anonymous entries; set to a number to bound the per-client cache independently of the pool size.

The Named part of the per-client cache (statements created with an explicit name via PREPARE or the extended-query Parse) is always unbounded — this knob does not affect it. Named statements stay cached for the lifetime of the client connection.

Default: not set (inherits prepared_statements_cache_size).

query_interner_gc_interval_seconds

The query interner runs a two-cycle mark-and-sweep collector. Named entries are evicted when nothing outside the interner holds the Arc<str>; anonymous entries are evicted when idle longer than query_interner_anon_idle_ttl_seconds.

This knob controls how often the collector wakes up. The actual sweep tick is gc_interval / 4, so an entry marked on cycle N has roughly a quarter-interval before cycle N+1 evicts it; any access during that window clears the mark.

Lower values shrink the interner faster after disconnect waves at the cost of more CPU. Setting this to 0 is rejected at startup.

Restart-only: changes to this knob take effect only after a restart; a config reload won't change the running sweep cadence.

Default: 60.

query_interner_anon_idle_ttl_seconds

Bounds the upper memory cost of pg_doorman remembering the SQL text of an anonymous prepared statement after the last Bind or Parse referencing the same hash. Once an anonymous entry has been idle longer than this many seconds it is marked, then evicted on the next sweep that still sees it as idle.

Setting this to 0 disables TTL eviction entirely. Anonymous entries live until the process restarts. This matches the pre-3.7 behaviour and is the right choice for legacy deployments that rely on cross-batch unnamed prepared statements; everywhere else, leave the default.

Live-reloadable: re-read on every sweep, so a config reload changes the effective TTL without a restart.

Default: 60.

message_size_to_be_stream

When a PostgreSQL DataRow message exceeds this threshold, pg_doorman switches to streaming mode: data is forwarded to the client in 4 KB chunks instead of buffering the entire message. This prevents OOM on queries that return very large rows (e.g., tables with big bytea/text columns). The threshold itself defaults to 1 MB.

Default: 1048576 (1 MB).

scaling_warm_pool_ratio

Warm pool ratio as a percentage (0-100). When the pool size is below this threshold of max_size, new connections are created immediately. Above this threshold, the pool first spins via fast retries, then enters an event-driven anticipation loop that waits for a returned idle connection. The loop is bounded by the client's remaining query_wait_timeout minus a 500 ms reserve for the create path, so it cannot push the caller past its own wait deadline.

Default: 20.

scaling_fast_retries

Number of fast retries using yield_now() for low-latency waiting when checking out connections above the warm pool threshold. Each retry takes approximately 1-5μs. After exhausting fast retries, the pool enters an event-driven anticipation loop bounded by the client's remaining query_wait_timeout.

Default: 10.

scaling_max_parallel_creates

Bounded burst limiter for connection creation. Without this cap, N parallel timeout_get callers that miss the idle pool each independently issue a backend connect, producing thundering-herd bursts under load. With the cap, only this many creates run concurrently per pool; the rest wait briefly on a Notify and then either pick up a freshly returned idle connection or take the next create slot. Default 2 is a compromise between throughput and burst smoothing.

Default: 2.

max_memory_usage

Total memory budget for internal buffers holding in-flight query data across all client connections. When this limit is reached, pg_doorman rejects new queries with an error until existing queries complete and free their buffers. Protects the pooler process from OOM under heavy load or large result sets.

Default: 268435456 (256 MB).

shutdown_timeout

During graceful shutdown (SIGTERM), pg_doorman waits up to this long for in-flight transactions to complete before forcibly closing connections.

Default: 10000 (10 sec).

proxy_copy_data_timeout

Maximum time to wait for data copy operations during proxying, in milliseconds.

Default: 15000 (15 sec).

server_tls_mode

TLS mode for outgoing connections to PostgreSQL servers.

  • allow — Try plain first; if server rejects, retry with TLS. Matches libpq sslmode=allow (default).
  • disable — TLS is not used.
  • prefer — TLS is used if the server supports it; plain connection otherwise.
  • require — TLS is required, but the server certificate is not verified.
  • verify-ca — TLS is required and the server certificate is verified against server_tls_ca_cert.
  • verify-full — TLS is required, the certificate is verified, and the server hostname must match the certificate.

Default: "allow".

server_tls_ca_cert

CA certificate for verifying PostgreSQL server certificates. Required when server_tls_mode is verify-ca or verify-full.

Default: None.

server_tls_certificate

Client certificate for mTLS with PostgreSQL servers. Pair with server_tls_private_key.

Default: None.

server_tls_private_key

Private key for the mTLS client certificate. Pair with server_tls_certificate.

Default: None.

hba

The list of IP addresses from which it is permitted to connect to the pg-doorman.

Default: [].

pg_hba

New-style client access control in native PostgreSQL pg_hba.conf format. This allows you to define fine-grained access rules similar to PostgreSQL, including per-database, per-user, address ranges, and TLS requirements.

You can specify general.pg_hba in three ways:

  • As a multi-line string with the contents of a pg_hba.conf file
  • As an object with path that points to a file on disk
  • As an object with content containing the rules as a string

Examples:

[general]
# Inline content (triple-quoted TOML string)
pg_hba = """
# type   database  user   address         method
host     all       all    10.0.0.0/8      md5
hostssl  all       all    0.0.0.0/0       scram-sha-256
hostnossl all      all    192.168.1.0/24  trust
"""

# Or load from file
# pg_hba = { path = "./pg_hba.conf" }

# Or embed as a single-line string
# pg_hba = { content = "host all all 127.0.0.1/32 trust" }

Supported fields and methods:

  • Connection types: local, host, hostssl, hostnossl (TLS-aware matching is honored)
  • Database matcher: a name or all
  • User matcher: a name or all
  • Address: CIDR form like 1.2.3.4/32 or ::1/128 (required for non-local rules)
  • Methods: trust, md5, scram-sha-256 (unknown methods are parsed but treated as not-allowed by the checker)

Precedence and compatibility:

  • general.pg_hba supersedes the legacy general.hba list. You cannot set both at the same time; configuration validation will reject this combination.
  • Rules are evaluated in order; the first matching rule decides the outcome.

Behavior of method = trust:

  • When a matching rule has trust, PgDoorman will accept the connection without requesting a password. This mirrors PostgreSQL behavior.
  • Specifically, if trust matches, PgDoorman will skip password verification even if the user has an md5 or scram-sha-256 password stored. This affects both MD5 and SCRAM flows.
  • TLS constraints from the rule are respected: hostssl requires TLS, hostnossl forbids TLS.

Admin console access:

  • general.pg_hba rules apply to the special admin database pgdoorman as well.
  • This means you can allow admin access with the trust method when a matching rule is present, for example:
    host  pgdoorman  admin  127.0.0.1/32  trust
    

Notes and limitations:

  • Only a minimal subset of pg_hba.conf is supported that is sufficient for most proxy use-cases (type, database, user, address, method). Additional options (like clientcert) are currently ignored.
  • For authentication methods other than trust, PgDoorman performs the corresponding challenge/response with the client.
  • For Talos/JWT/PAM flows configured at the pool/user level, trust still bypasses the client password prompt; however, those modes may be used when trust does not match.

pooler_check_query

When a client sends this exact query as a SimpleQuery, pg_doorman serves it through a per-pool response cache. The first matching probe in each pool's lifetime is forwarded to PostgreSQL and the full response is captured. Subsequent matching probes are answered from the cache without touching the backend.

The cache is keyed by the query string. A RELOAD that changes pooler_check_query invalidates the cache on the next ping; the new value triggers one fresh backend probe and is then served from cache until the value changes again. A reload that keeps the same value keeps the cached response. ErrorResponse from the backend is forwarded to the client unchanged and is never cached, so the next probe retries against PostgreSQL.

Cold-pool behavior changed: the first probe per pool now does one PostgreSQL round-trip even for the default ;. If PostgreSQL is unreachable at that moment, the probing client sees a probe failure instead of an unconditional OK. The earlier hardcoded local answer reported the pooler as healthy even when PostgreSQL was down, and made non-empty values such as select 1 return an empty response.

Operator contract. The query must be stable: the same input must always produce the same bytes, with no side effects. Safe values: ;, select 1, select 'pg_doorman', select version().

Unsafe values that the cache will silently freeze:

  • select now(), select clock_timestamp() — the cached timestamp never advances.
  • select pg_is_in_recovery() — a failover flips the role on PostgreSQL but the cached response still reports the old role.
  • select count(*) from <table> — the cached count is whatever the first probe observed.
  • UPDATE, INSERT, DELETE, CALL, DO — the side effect runs once and the success response is cached forever.

Cache hit rate is exported as two counters without labels: pg_doorman_pooler_check_query_backend_total (probes forwarded to PostgreSQL) and pg_doorman_pooler_check_query_cache_total (probes served from cache). The ratio cache_total / (cache_total + backend_total) is the hit rate.

Default: ";".

startup_parameters

Map of PostgreSQL configuration parameter names to string values. pg_doorman writes them into each new backend StartupMessage; PostgreSQL stores them as the session reset defaults, so client RESET ALL / DISCARD ALL returns to these values.

Cascade order: general.startup_parameters, then pools.<name>.startup_parameters, then the optional startup_parameters JSON column returned by passthrough auth_query. Later layers win per key. Dedicated-mode auth_query pools ignore the per-user column because one shared backend serves multiple roles.

Validation at config load rejects reserved protocol keys (user, database, replication, options, anything starting with _pq_.), invalid GUC names, null bytes, and per-level maps that exceed the startup-parameter budget. Before each backend startup, pg_doorman checks the resolved parameter set against PG's MAX_STARTUP_PACKET_LENGTH (10 000 bytes). Any overflow rejects backend startup with SQLSTATE 53400 (configuration_limit_exceeded) instead of sending a partial or empty StartupMessage.

If PostgreSQL rejects a parameter at backend startup, pg_doorman returns PostgreSQL's ErrorResponse to the client unchanged. There is no retry with the key removed, and pg_doorman does not automatically disable that key for the pool. The cumulative count is exported as pg_doorman_backend_startup_parameter_errors_total{pool, sqlstate}; the parameter name and username are written to the corresponding warning log line.

Inspect the resolved per-pool values with SHOW STARTUP_PARAMETERS or the /api/pools REST endpoint.

Default: {} (empty).