Feature Request
| Q |
A |
| New feature |
yes |
| Affected drivers |
pdo_pgsql, pgsql (native) |
| DBAL version |
3.10.x and current 4.4.x |
Summary
The PostgreSQL drivers build the connection string from a fixed whitelist of
parameters and silently drop everything else. As a result, the libpq TCP-resilience
keywords — keepalives, keepalives_idle, keepalives_interval, keepalives_count,
tcp_user_timeout (and connect_timeout) — cannot be configured through DBAL, even
though libpq and ext-pgsql/pdo_pgsql fully support them.
I'd like to propose forwarding these keywords to the connection string.
Motivation
When a TCP connection to PostgreSQL is silently cut mid-query (e.g. a flaky link
between two datacenters, a stateful firewall/NAT dropping an idle entry, a load
balancer reset without RST), the PHP process blocks in libpq's recv() until the
kernel gives up. With the Linux default net.ipv4.tcp_retries2 = 15, that is
~15 minutes per stuck request, which can exhaust the worker/FPM pool and cascade
into an outage.
We hit exactly this in production (queries hanging for a consistent ~944 s ≈
tcp_retries2=15, failing with SQLSTATE[HY000] [7] could not receive data from server: Connection timed out), while healthy query durations are sub-second
(p99 ≈ 30 ms). The standard remedy is libpq's keepalives + tcp_user_timeout, which
bound dead-peer detection to a few seconds — but there is currently no way to set them
via DBAL.
Current behavior
Doctrine\DBAL\Driver\PDO\PgSQL\Driver::constructPdoDsn() only appends:
host, port, dbname, sslmode, sslrootcert, sslcert, sslkey, sslcrl,
application_name, gssencmode.
Doctrine\DBAL\Driver\PgSQL\Driver::constructConnectionString() (native) only keeps:
host, hostaddr, port, dbname, user, password, sslmode, gssencmode.
Any other connection parameter passed via DriverManager::getConnection([...]) is
ignored, so these keywords never reach libpq.
Proposed change
Forward the libpq TCP keywords in both PgSQL drivers' connection-string builders,
in the same explicit style already used for the ssl* keywords:
keepalives
keepalives_idle
keepalives_interval
keepalives_count
tcp_user_timeout
connect_timeout
// example, e.g. DriverManager::getConnection()
$conn = DriverManager::getConnection([
'driver' => 'pdo_pgsql',
'host' => 'db.internal',
'dbname' => 'app',
'keepalives' => 1,
'keepalives_idle' => 10,
'tcp_user_timeout' => 15000, // ms
]);
All of these are standard libpq connection keywords
(https://www.postgresql.org/docs/current/libpq-connect.html), already accepted by
pdo_pgsql / ext-pgsql DSNs today.
Workaround
Today this requires a custom driver_class that subclasses AbstractPostgreSQLDriver
and re-implements the DSN builder (the stock PDO driver is final), just to append a
handful of keywords — which means duplicating connect/DSN logic that has to be kept in
sync with DBAL.
Open question for maintainers
Would you prefer:
- Enumerating these specific keywords (matches the current
ssl* / gssencmode
style), or
- A generic passthrough of a documented set of libpq keywords?
Happy to open a PR for whichever direction you'd like (covering both the PDO and native
drivers, plus docs/tests).
Environment
- DBAL: 3.10.x (also verified the gap on
4.4.x)
- PHP: 8.3, ext-pdo_pgsql (libpq 18)
- PostgreSQL: 16
Feature Request
pdo_pgsql,pgsql(native)4.4.xSummary
The PostgreSQL drivers build the connection string from a fixed whitelist of
parameters and silently drop everything else. As a result, the libpq TCP-resilience
keywords —
keepalives,keepalives_idle,keepalives_interval,keepalives_count,tcp_user_timeout(andconnect_timeout) — cannot be configured through DBAL, eventhough libpq and ext-pgsql/pdo_pgsql fully support them.
I'd like to propose forwarding these keywords to the connection string.
Motivation
When a TCP connection to PostgreSQL is silently cut mid-query (e.g. a flaky link
between two datacenters, a stateful firewall/NAT dropping an idle entry, a load
balancer reset without RST), the PHP process blocks in libpq's
recv()until thekernel gives up. With the Linux default
net.ipv4.tcp_retries2 = 15, that is~15 minutes per stuck request, which can exhaust the worker/FPM pool and cascade
into an outage.
We hit exactly this in production (queries hanging for a consistent ~944 s ≈
tcp_retries2=15, failing withSQLSTATE[HY000] [7] could not receive data from server: Connection timed out), while healthy query durations are sub-second(p99 ≈ 30 ms). The standard remedy is libpq's keepalives +
tcp_user_timeout, whichbound dead-peer detection to a few seconds — but there is currently no way to set them
via DBAL.
Current behavior
Doctrine\DBAL\Driver\PDO\PgSQL\Driver::constructPdoDsn()only appends:host,port,dbname,sslmode,sslrootcert,sslcert,sslkey,sslcrl,application_name,gssencmode.Doctrine\DBAL\Driver\PgSQL\Driver::constructConnectionString()(native) only keeps:host,hostaddr,port,dbname,user,password,sslmode,gssencmode.Any other connection parameter passed via
DriverManager::getConnection([...])isignored, so these keywords never reach libpq.
Proposed change
Forward the libpq TCP keywords in both PgSQL drivers' connection-string builders,
in the same explicit style already used for the
ssl*keywords:keepaliveskeepalives_idlekeepalives_intervalkeepalives_counttcp_user_timeoutconnect_timeoutAll of these are standard libpq connection keywords
(https://www.postgresql.org/docs/current/libpq-connect.html), already accepted by
pdo_pgsql/ ext-pgsql DSNs today.Workaround
Today this requires a custom
driver_classthat subclassesAbstractPostgreSQLDriverand re-implements the DSN builder (the stock PDO driver is
final), just to append ahandful of keywords — which means duplicating connect/DSN logic that has to be kept in
sync with DBAL.
Open question for maintainers
Would you prefer:
ssl*/gssencmodestyle), or
Happy to open a PR for whichever direction you'd like (covering both the PDO and native
drivers, plus docs/tests).
Environment
4.4.x)