504 appears when Nginx was waiting for a response from the backend — php-fpm, Apache, Node.js — and timed out. Nginx itself is working fine. The problem is either that the backend hung, or that the script runs longer than the configured timeouts allow. Two different scenarios, two different fixes.
First: Find Where the 504 Is Happening
Before changing timeouts — check how often the error occurs and on which URLs:
grep " 504 " /var/log/nginx/access.log | tail -50
More details from the error log:
grep "504" /var/log/nginx/error.log | tail -30
If 504 is on one specific URL — likely a heavy script or a hung process. If it's everywhere — server overload or a crashed php-fpm.
Check Server Resources
If the server is overloaded — increasing timeouts will only delay the error, not fix it.
Free RAM:
free -h
CPU load and top processes:
htop
php-fpm status:
systemctl status php8.1-fpm
If php-fpm is consuming all CPU cores or has crashed — that is the cause of the 504. Fix: optimize scripts, add caching, or upgrade the VPS.
Increase Timeouts for php-fpm (FastCGI)
If a script intentionally runs for a long time — importing a large file, generating a report, processing video — Nginx by default cuts the connection after 60 seconds.
Open the virtual host config or the location block where fastcgi is used:
sudo nano /etc/nginx/sites-available/mysite
Add inside location ~ \.php$:
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
The three directives cover different phases: connecting to php-fpm, sending data, and waiting for a response. All three need to be set for long scripts — otherwise 504 may return at a different stage.
Test config and reload:
sudo nginx -t && sudo systemctl reload nginx
Increase Timeouts for Reverse Proxy (Apache, Node.js)
If Nginx proxies requests to another server — use proxy directives. Add inside the server or location block:
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
After changes:
sudo nginx -t && sudo systemctl reload nginx
Also Increase the Timeout on the php-fpm Side
Nginx can wait patiently, but if php-fpm terminates the script first — 504 returns. Set the execution timeout in the pool config:
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
request_terminate_timeout = 300
And in php.ini:
sudo nano /etc/php/8.1/fpm/php.ini
max_execution_time = 300
Restart php-fpm:
sudo systemctl restart php8.1-fpm
Find Slow Scripts via slow-log
If 504 occurs for users intermittently and the problematic script is unknown — enable slow-log in php-fpm. It records scripts that took longer than the configured threshold.
Open the pool config:
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
Add:
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 5s
Restart php-fpm:
sudo systemctl restart php8.1-fpm
Watch what accumulates:
tail -f /var/log/php-fpm/www-slow.log
The log contains a stack trace — shows which function or database query is the bottleneck. More precise than guessing from access.log URLs.
Check php-fpm Worker Count
If all workers are busy — new requests queue up and cause 504 even on fast scripts.
Check current php-fpm processes:
ps aux | grep php-fpm | grep -v grep | wc -l
Compare with pm.max_children in the pool config. If the process count equals max_children — all workers are occupied, increase it:
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
Quick Reference
| Cause of 504 | Fix |
|---|---|
| Script runs longer than Nginx timeout | fastcgi_read_timeout 300 in location |
| Nginx proxying to Apache/Node.js | proxy_read_timeout 300 in server/location |
| php-fpm terminates script too early | request_terminate_timeout = 300 in www.conf |
| All php-fpm workers busy | Increase pm.max_children |
| Server overloaded | htop, free -h, optimize or upgrade VPS |
| Unknown which script is slow | Enable slowlog in php-fpm |
| Find 504 URLs in logs | grep " 504 " /var/log/nginx/access.log |