Troubleshooting guide · website-errors · Published 2026-08-15 · 4 min read
Nginx 502 and 504 with PHP-FPM
Diagnose and fix Nginx 502 and 504 errors caused by a down, slow or exhausted PHP-FPM pool.
- ·502 vs 504
- ·Find the cause
- ·Tune the pool
When Nginx sits in front of PHP-FPM, a 502 Bad Gateway and a 504 Gateway Timeout both point at the PHP process, but they describe different failures. A 502 usually means Nginx could not get a reply because PHP-FPM was not there to take the request. A 504 means PHP-FPM was there but did not finish answering in time. Telling the two apart points you to the right log and the right fix.
502 vs 504
A 502 appears when Nginx cannot connect to PHP-FPM at all, such as when the service stopped, the socket file is missing or the Unix socket path in fastcgi_pass no longer exists. A 504 appears when Nginx connects but the request exceeds fastcgi_read_timeout, which defaults to 60 seconds. In practice both appear together during pool exhaustion, because once every worker slot is busy, new requests either cannot connect (502) or wait past the read timeout (504).
Find the cause
Check the PHP-FPM logs first, not just the Nginx access log. The messages that matter are:
server reached pm.max_children,already running 5 processes, orpool seems busy, which mean the pool is exhausted.- A restart of the FPM service or the socket, which can explain a burst of 502s.
- Slow-log entries, which point at a specific script that occupies a worker for tens of seconds.
From the Nginx side, upstream timed out (110: Connection timed out) while reading response header from upstream in the error log pinpoints a read-timeout 504. connect() failed (111: Connection refused) while connecting to upstream pinpoints a 502, usually from a dead socket or stopped pool.
Tune the pool
If the pool is exhausted, compute a sane pm.max_children from available memory rather than leaving the default of 5, which is low for any busy site. A rough budget is available memory divided by the average worker memory, leaving headroom for the OS and database. A dynamic model that recycles workers is safer than a fixed count:
pm = dynamic
pm.max_children = 25
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 10
pm.max_requests = 500
pm.max_requests recycles a worker after it has handled its allotment of requests, which clears memory that leaks over time. Then line up the timeouts: keep fastcgi_connect_timeout short (about 10 seconds), set fastcgi_read_timeout high enough for genuinely slow requests, and pair it with request_terminate_timeout in PHP-FPM so the pool kills a stuck script before Nginx gives up. Two or more timeouts fighting each other turn an occasional slow script into a site-wide 504.
When it is not the pool
A 504 is often caused by one slow script, not capacity. A missing database index, a synchronous third-party API call with no timeout, or a backup running on the same server can all hold workers for the full timeout window. Profile the slow request with the FPM slowlog before raising limits, because raising timeouts without fixing the slow code only delays the failure. Disk I/O saturation can also produce 504 even when CPU looks idle.
Prevention
Watch the PHP-FPM max_children reached counter and the slowlog as early warnings. Right-size the pool for real traffic, enable object or full-page caching to reduce concurrent PHP requests, and keep one slow path from dragging down every worker. Tedious as it sounds, the routine is the fix: log, measure one worker, size the pool, set matching timeouts.
Related failure modes
The same 502 and 504 codes appear with other back ends. The general bad-gateway and gateway-timeout articles describe the shared diagnosis, and the WordPress-specific guide covers the plugin and theme causes common on CMS sites.