These three status codes are often treated as identical, but their root causes are completely different. Misidentifying the code leads to wrong troubleshooting directions—checking for timeouts when you have a 502, or checking processes when you have a 504, is a waste of time.
The only commonality among them is: the request reached the gateway, but the desired result was not obtained. The difference lies in why the result was not obtained.
What Each Code Represents
| Status Code | Literal Meaning | Substance | Most Common Cause |
|---|---|---|---|
| 502 | Bad Gateway | Upstream provided an invalid response | php-fpm not running / Connection refused / Process crash |
| 503 | Service Unavailable | Service is temporarily unavailable | Maintenance mode / Rate limiting / All upstreams down |
| 504 | Gateway Timeout | Upstream did not respond within the time limit | Slow script execution / Slow database queries / External API hanging |
Remember this heuristic: A 502 means “connected, but what they said was wrong”; a 504 means “connected, but they didn’t say anything”. One has a response issue; the other has no response at all.
Reading Key Information from Error Logs
Nginx error logs directly state the cause, which is the fastest way to locate the issue:
tail -100 /var/log/nginx/error.log
# Or filter specifically for upstream-related issues
grep -E 'upstream|connect()|timed out' /var/log/nginx/error.log | tail -30
| Log Keyword | Meaning | Corresponding Status Code |
|---|---|---|
connect() failed (111: Connection refused) |
No one listening on port | 502 |
connect() failed (113: No route to host) |
Network/Firewall blocking connection | 502 |
upstream prematurely closed connection |
Upstream crashed during processing | 502 |
upstream timed out |
Upstream timed out without responding | 504 |
no live upstreams |
All backends are unavailable | 503 |
502: First, Confirm if the Upstream is Alive
# ① Is php-fpm running?
systemctl status php-fpm
# ② Is the port/socket listening?
ss -lntp | grep -E '9000|php'
ss -lx | grep php
# ③ Are the nginx upstream addresses correct?
grep -E 'fastcgi_pass|proxy_pass' /etc/nginx/conf.d/*.conf
# ④ Manually test the upstream (verification outside nginx)
SCRIPT_FILENAME=/var/www/html/index.php
REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
# ⑤ Check if php-fpm process count is sufficient (key for intermittent 502s)
ps aux | grep -c '[p]hp-fpm'
tail -50 /var/log/php-fpm/error.log
The most common cause of intermittent 502 errors is insufficient process count. When concurrency spikes, requests queue up, and nginx fails to connect. The characteristic is “normal under low load, errors appear when traffic increases.”
; /etc/php-fpm.d/www.conf
pm.max_children = 50 ; Adjust based on memory, do not copy blindly
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
# Check if processes are maxed out (reaching max_children means it's insufficient)
ps aux | grep -c '[p]hp-fpm'
grep -i 'max_children' /var/log/php-fpm/error.log | tail
504: Confirm What is Slow
# ① What are the current timeout settings?
grep -E 'fastcgi_read_timeout|fastcgi_connect_timeout|proxy_read_timeout'
/etc/nginx/conf.d/*.conf
# ② Reproduce the slow request and check duration
curl -o /dev/null -s -w 'Total Time: %{time_total}s TTFB: %{time_starttransfer}sn'
https://example.com/
# ③ Is the database or external interface slow?
# Enable MySQL slow query log, or check currently executing statements directly
mysqladmin processlist
location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_read_timeout 60s; # Default is 60s; increase for long tasks
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 60s;
}
Increasing the timeout only delays the error; it does not fix the problem. If a script truly needs two minutes to run, the correct approach is to make it asynchronous (queue the task, execute in background), rather than increasing the timeout to 200 seconds—that just replaces a 504 with “connection pool exhausted.”
503: Confirm if It Was Intentional
# ① Is it maintenance mode? (WordPress leaves .maintenance)
ls -la /var/www/html/.maintenance
# ② Are all backend services unavailable?
systemctl status php-fpm nginx mysql
# ③ Was rate limiting triggered?
grep -iE 'limiting|rate' /var/log/nginx/error.log | tail
The special thing about 503 is: it might be set by you intentionally (maintenance page, rate limiting). First confirm if it’s your own configuration before looking for faults.
Decision Tree
Gateway Errors
├─ 502 Bad Gateway
│ ├─ Connection refused → Upstream not started / Wrong port
│ ├─ Prematurely closed → Upstream crashed during processing → Check PHP error logs
│ ├─ No route to host → Firewall / Network issue
│ └─ Intermittent → Insufficient php-fpm processes, check max_children
├─ 503 Service Unavailable
│ ├─ Has .maintenance → Maintenance mode residue, delete it
│ ├─ No live upstreams → All backends down
│ └─ Rate limiting logs → Rate limit triggered
└─ 504 Gateway Timeout
├─ Upstream timeout → Increasing timeout is a mitigation; optimize the slow component
├─ Database slowness → Slow queries / Indexes
└─ External API hanging → External calls must have timeouts and fallback mechanisms
Scenario Analysis: Alternating 502/504, Restarting Keeps Failing
Symptom: A site intermittently reports errors, switching between 502 and 504.
Restarting the backend service restores functionality for a while, but the issue returns after a few hours.
- Differentiate direction by status code → 502 means the frontend cannot get a normal response from the backend; 504 means the backend did not respond in time.
Alternating occurrences indicate the backend is in a state of “sometimes completely unavailable, sometimes barely responsive but slow.” - Check if the backend is actually down → Processes are running, so it’s not a total crash,
but rather processing capacity is overwhelmed or blocked. - Check backend process count and queue status → The allowed number of worker processes is too low and already full.
New requests queue up, and if they exceed the tolerance time, they become 504s. - Investigate why the queue is full → There is a batch of extremely long-running requests (involving external calls)
that occupy worker processes for extended periods. - Distinguish if it’s a resource shortage → Check if memory triggered system protection (OOM killer) to kill processes.
This step rules out “processes being repeatedly killed” causing 502s. - Adjust based on root cause → Set upper limits for external call timeouts and appropriately increase worker processes,
preventing slow requests from occupying slots for too long.
# Check if backends were killed or blocked
dmesg -T | grep -i 'oom|killed process' | tail
systemctl status php-fpm --no-pager | head -15
# Check if process pool is full
# PHP-FPM status page or:
ps -eo pid,cmd --sort=-etime | grep -c 'php-fpm'
tail -50 /var/log/php-fpm/error.log | grep -i 'server reached|busy'
# Confirm upstream error type on nginx side
grep -E 'upstream (timed out|prematurely closed|sent invalid)' /var/log/nginx/error.log | tail -10
# External calls MUST have timeouts; otherwise, slow requests will occupy worker processes indefinitely
# fastcgi_read_timeout 30s; proxy_read_timeout 30s;
Root Cause: External calls lack timeout limits, causing slow requests to occupy backend worker processes for long periods;
after the process pool is filled, new requests queue up, leading to alternating 502 and 504 errors. Restarting only clears the queue; the root cause remains unchanged.
Two key takeaways:
- When 502 and 504 alternate, suspect “backend saturated by slow requests” first, rather than “backend is down.”
Processes are running but unable to respond, which is a typical sign of resources being occupied long-term. - All external calls must have timeouts.
Unlimited external waits will exhaust the backend’s limited worker slots; this is the most common root cause of such failures.
8 Common Pitfalls
- Not distinguishing between the three codes: Checking processes for 502 and timeouts for 504 are completely different directions.
- Ignoring error.log: The logs already contain the cause, which is much faster than guessing.
- Increasing timeout for 504: Masks the problem; long tasks should be made asynchronous.
- Restarting for 502: Restores function temporarily but recurrence is inevitable; restarting when process count is insufficient only clears the queue.
- Only checking nginx, ignoring PHP logs: The cause of
prematurely closedlies on the php-fpm side. - Changing config without reloading: After
nginx -t, you must runnginx -s reload. - Adjusting max_children without checking memory: Can trigger OOM, making the problem worse than the original issue.
- Ignoring external interfaces: When calling third parties without timeout settings, the cause of 504 may lie with the third party.
Real Customer Feedback (From Cloud Market Reviews and Inquiries for Similar Products)
The following excerpts are taken from real buyer reviews and inquiries for similar operations services on Alibaba Cloud / Tencent Cloud / Huawei Cloud Cloud Markets (service providers include our store and competitors, provided here for reference only, not fictional tickets from this site):
b****4 Rating: 5.0 Jun 23, 2025 16:57 b****4 Rating: 5.0 Jun 23, 2025 16:56 Jian****Wei Rating: 5.0 Jan 20, 2021 15:03 Excellent technical skills, very fast! It turned out to be a Trojan causing Baidu global hijacking!!!!!!1 f****u Rating: 5.0 Jan 02, 2021 20:43 Thanks for assisting in maintaining Yuncai’s normal operation. 1****1 Rating: 5.0 Nov 20, 2020 10:03 Consistently good service 1****1 Rating: 5.0 Nov 17, 2020 09:13 Thank you for the consistently good service. 1****1 Rating: 5.0 Sep 25, 2020 15:42 Many thanks. 1****1 Rating: 5.0 Aug 24, 2020 15:34 Many thanks to your company’s technical staff 1****1 Rating: 5.0 Jul 24, 2020 09:49 Many thanks! 1
10***77 2022-09-19 5.0 Affordable price | Skilled technology | Patient and professional Received filing rectification notice, found this service just in time, handled quickly 10***49 2022-04-12 5.0 On-time delivery | Affordable price | Skilled technology Needed rectification, configured quickly, not bad