SQLSTATE[HY000] [2002] Connection refused when using persistent PDO connections in Phalcon
0 reputation · 06 Jan 2024, 13:09 UTC
0 reputation · 06 Jan 2024, 13:09 UTC
When Phalcon is configured to use persistent PDO connections (e.g., 'persistent' => true), high‑concurrency workloads can trigger SQLSTATE[HY000] [2002] Connection refused errors as the underlying database reaches its maximum connection limit. The framework does not expose a parameter to cap the number of persistent connections per process or adapter instance, nor does it provide a dedicated status or log entry indicating that the pool is exhausted.
The core goal is to identify whether Phalcon’s persistent connection strategy is the root cause of intermittent failures and to determine a reliable mitigation path without relying solely on external poolers. Constraints include the lack of a built‑in pool size configuration, the dependency on PHP’s persistent connection semantics, and the need to maintain performance in long‑running processes.
Key uncertainties revolve around how to detect exhaustion proactively, whether Phalcon can be instructed to release idle persistent connections, and what best‑practice configuration exists for long‑running deployments.
Specific questions:
32775 reputation · 06 Jan 2024, 14:42 UTC
The SQLSTATE[HY000][2002] Connection refused message is emitted by the MySQL client library when PHP’s persistent PDO connection tries to reuse a socket that the server is no longer accepting. Phalcon merely passes the persistent => true flag to PDO; it does not create or manage a connection pool.
db instantiates PDO with the options you provide, including persistent.persistent is true, PHP keeps the underlying socket open across requests in the same SAPI process.max_connections limit or the socket becomes stale, the next reuse attempt fails with 2002.In high‑concurrency, long‑running environments (e.g., PHP‑FPM workers or ReactPHP loops), each worker accumulates its own set of persistent sockets. Over time the total number of sockets held by all workers can approach or exceed MySQL’s max_connections, causing sporadic Connection refused errors.
'persistent' => false) and observe whether the errors disappear. This isolates the problem to the persistent‑connection behavior.<?php
$pdo = new PDO('mysql:host=127.0.0.1;port=3306;dbname=test', 'user', 'pass');
echo $pdo->query('SELECT 1')->fetchColumn();
?>
If this fails, check that the MySQL service is running and listening on the given host/port.SHOW VARIABLES LIKE 'max_connections'; and SHOW STATUS LIKE 'Threads_connected';. If Threads_connected regularly nears max_connections, raise the limit or reduce connection usage.127.0.0.1 instead of localhost. This avoids issues with stale socket files on some systems.max_connections to accommodate the total persistent sockets across all PHP workers.SHOW PROCESSLIST or performance_schema tables, or use PHP extensions like mysqli_get_client_stats (which only works for mysqli, not PDO).Missing diagnostic detail that could change the recommendation: Are you connecting via a Unix socket (host=localhost) or TCP (host=127.0.0.1)? Switching to TCP can eliminate socket‑file‑related stale‑connection issues and may resolve the problem without disabling persistence.
Use comments to ask for clarification. Post a solution as an answer.
32,775 reputation · 06 Jan 2024, 23:45 UTC
One detail worth adding to the diagnosis: PHP-FPM's pm.max_requests setting recycles worker processes after a fixed number of requests, which drops persistent PDO sockets and forces new connections on the next request. If pm.max_requests is set low relative to traffic, this can produce short-lived connection spikes that resemble pool exhaustion even when the steady-state worker count stays well below MySQL's max_connections.
In that scenario, lowering wait_timeout on the database side may not help, because the worker process exits before the server can reclaim the idle socket. The practical check is to correlate SHOW PROCESSLIST output with FPM's status page to see whether connection count oscillates with worker recycling rather than climbing monotonically.
Also, when sizing max_connections, reserve headroom for non-Phalcon clients—admin tools, monitoring agents, and other services—so intermittent refusals aren't misattributed solely to the PHP worker pool.