Troubleshoot Nginx FastCGI 504 timeouts with PHP-FPM
Identify the timeout that fired, inspect PHP-FPM slow requests, and align application deadlines without hiding pool exhaustion.
A 504 from an Nginx FastCGI gateway means an upstream operation timed out. Inspect the error log to distinguish connection, write, and read failures before increasing a timeout. Slow database calls, blocked external requests, and an exhausted PHP-FPM pool need different fixes.
Check the three timeout layers
For a root-based PHP site, a configuration fragment might be:
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 120s;
}
Use the real socket and document root. Ensure included files do not already define a conflicting SCRIPT_FILENAME.
fastcgi_read_timeout defaults to 60 seconds and measures the gap between successive upstream reads, not the whole response. Likewise, the send timeout measures gaps between writes. Increasing the read timeout helps only when that is the limit being reached.
PHP-FPM's pool setting controls termination of a worker handling a request:
request_terminate_timeout = 120s
PHP's own script setting is separate:
max_execution_time = 120
These numbers are examples, not a required ordering. On non-Windows systems, PHP execution time generally excludes time spent in activities such as system calls and database queries; it is not a reliable wall-clock request deadline. A worker terminated by FPM may produce a 502 instead of a 504. Choose application and dependency deadlines so work can fail cleanly before the outer gateway gives up, and verify behavior under the real workload.
Reload the appropriate Nginx and PHP-FPM instances after validating their configurations.
Find the slow work
Enable an FPM slow log in the affected pool:
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 5s
Match its sampled stack to database slow logs or instrumented spans for the same request. Traces reveal only operations actually instrumented; missing spans do not prove that a dependency was fast.
For site-wide failures, inspect pool saturation, queueing, and pm.max_children using a protected FPM status endpoint. Do not expose the status page publicly. Size the pool from measured worker memory, the memory budget available to FPM, and CPU/database capacity. Simple division by average RSS is only a starting estimate; include workload variation and headroom.
Move long work out of the request path
Reports and large exports often fit a queue-backed job with a status endpoint better than a minutes-long synchronous HTTP request. Increasing every deadline can keep workers occupied longer and worsen queueing.
FAQ
Why does a larger read timeout not help?
Confirm the correct location was reloaded and identify the actual timeout. A CDN, load balancer, application, or dependency may enforce a shorter deadline. Consult that service's current limits rather than assuming a fixed vendor-wide number.
Can only one endpoint receive a longer timeout?
Yes, use a location that actually handles that FastCGI request, preserving its script mapping and other FastCGI parameters. An internal redirect to a shared PHP location can change which settings apply.
Why did 504 turn into 502?
FPM may now terminate or reset the connection first. Correlate process exits and FPM logs instead of treating the changed status as improvement.
References: FastCGI timeouts, PHP-FPM pool configuration, PHP execution limits.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan