A 504 means the page was still being built when Nginx stopped waiting. Nothing crashed. Something took longer than it is allowed to take, and the honest question is what.
Find the slow request
PHP-FPM writes a slow log if you ask it to, and it prints the exact function that was running when the clock ran out. That is the whole answer, so turn it on before changing anything else.
; in the pool config
request_slowlog_timeout = 5s
slowlog = /var/log/php8.3-fpm-slow.log
- Reload PHP-FPM — systemctl reload php8.3-fpm
- Reproduce the slow page — One request is enough.
- Read the trace — tail -60 /var/log/php8.3-fpm-slow.log - the top frame is what was running.
The three things it usually is
- An external call with no timeout. A payment gateway or an API that stopped answering will hold your page for as long as the socket stays open. Every outbound request needs its own timeout, and five seconds is generous.
- A query with no index. A table that was small last year is not small now. The slow query log names it.
- A loop over a directory. A folder that has grown to a hundred thousand files takes minutes to list.
Raising fastcgi_read_timeout makes the error go away and leaves the visitor staring at a blank tab for five minutes instead of one. Fix the wait, not the limit.
When raising it IS right
One case: a deliberate long job you triggered yourself - a migration, a large import - on a page only you use. Raise it for that location alone, never globally.
location = /admin/import.php {
fastcgi_read_timeout 600;
}
Anything a visitor can trigger belongs in a queue. The page starts the job and returns immediately; the job reports when it is done.