What is the maximum number of concurrent PHP-FPM workers that can safely run with MODX xPDO persistent connections enabled without exhausting MySQL connections?
0 reputation · 02 Aug 2020, 09:27 UTC
0 reputation · 02 Aug 2020, 09:27 UTC
Goal: Determine the appropriate PHP-FPM pm.max_children value that prevents intermittent MySQL 'Too many connections' errors when MODX Revolution's xPDO persistent_connection system setting is enabled.
Constraints/uncertainty: xPDO reuses a single PDO instance per request but does not share persistent connections across separate PHP-FPM workers; idle persistent connections remain open until MySQL's wait_timeout expires, and it is unclear whether each worker holds exactly one connection or additional connections during request processing.
Does each MODX request consume exactly one persistent connection when persistent_connection is true? How does MySQL's wait_timeout affect idle persistent connections from idle PHP-FPM workers? What formula can be used to calculate a safe pm.max_children limit given a target MySQL max_connections and expected MODX connection usage per worker?
28775 reputation · 02 Aug 2020, 10:39 UTC
To prevent "Too many connections" errors in MySQL when MODX xPDO persistent connections are enabled, your pm.max_children value must not exceed the available MySQL connection slots. Because each PHP-FPM worker maintains exactly one persistent PDO connection that persists across requests, the relationship is 1:1.
Use the following formula to determine your safe upper limit:
pm.max_children = (MySQL max_connections) - (Reserved Connections)
Example: If your MySQL max_connections is 151 and you reserve 11 slots for administrative access and cron jobs, your pm.max_children should be set to 140.
When persistent_connection is set to true in MODX, xPDO uses PDO::ATTR_PERSISTENT. This means the connection is not closed when the PHP script finishes; instead, it is cached by the PHP-FPM worker process. When that same worker handles a subsequent request, it reuses the existing connection.
Crucially, these connections are not shared between different PHP-FPM workers. If you have 50 workers, you will eventually have 50 idle connections sitting in MySQL, regardless of how many active requests are currently being processed.
MySQL's wait_timeout determines how long an idle connection stays open before the server forcibly closes it. While this can reclaim slots, relying on it is risky for MODX sites. If a worker is kept alive by PHP-FPM (e.g., using pm = dynamic or static) but the MySQL connection times out, the worker may encounter a "MySQL server has gone away" error upon the next request unless the driver handles the reconnection transparently.
mysql -e "SHOW VARIABLES LIKE 'max_connections';"
/etc/php/8.x/fpm/pool.d/www.conf) and set pm.max_children to the calculated value.mysql -e "SHOW STATUS LIKE 'Threads_connected';"
This calculation assumes that MODX is the only application using the database and that no custom plugins are manually opening secondary non-persistent connections. If your site uses external scripts or multiple xPDO instances per request, the per-worker connection count will increase, and you must lower pm.max_children accordingly.
Missing Diagnostic: To provide a specific numeric recommendation, the current value of your MySQL max_connections variable is required.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.