Home/Server & Website Managed Operations/How to Troubleshoot 502, 503, and 504 Errors: Nginx / PHP-FPM / Apache Logs and Checklist
Server & Website Managed Operations

How to Troubleshoot 502, 503, and 504 Errors: Nginx / PHP-FPM / Apache Logs and Checklist

The website suddenly becomes inaccessible, displaying 502 Bad Gateway, 503 Service Unavailable, or 504 Gateway Time-out. While these status codes may seem similar, they actually point to completely different failure layers and require entirely different handling approaches.

The key to troubleshooting such issues is not guessing, but reading the original error messages. The logs for nginx, php-fpm, and Apache are very clear—whether it’s a connection failure, rejection, or timeout, each has its corresponding log entry. By matching the keywords from the logs with the reference table below, you can usually pinpoint the root cause in one go.

First, Understand the Differences Between 502, 503, and 504

Status Code Meaning Nature
502 Bad Gateway The gateway received an invalid response from upstream Connection refused, rejected, dropped mid-stream, or abnormal response headers
503 Service Unavailable Upstream is unavailable All backends offline, resource exhaustion, or application actively rejecting requests
504 Gateway Time-out Upstream timed out No content returned within the specified time limit

In short: 502 means “received but incorrect,” 503 means “no one answered at all,” and 504 means “took too long”.

Read the Error Messages: Identify the Layer at a Glance

nginx Errors (FastCGI Scenario)

connect() failed (111: Connection refused) while connecting to upstream,
client: 192.0.2.1, server: example.com, request: "GET / HTTP/1.1",
upstream: "fastcgi://127.0.0.1:9000", host: "example.com"

upstream prematurely closed connection while reading response header from upstream,
client: 192.0.2.1, upstream: "fastcgi://127.0.0.1:9000"

recv() failed (104: Connection reset by peer) while reading response header from upstream

connect() to unix:/run/php-fpm/www.sock failed (13: Permission denied) while connecting to upstream

connect() to unix:/run/php-fpm/www.sock failed (2: No such file or directory) while connecting to upstream

upstream sent too big header while reading response header from upstream

Original Text for 503 and 504

no live upstreams while connecting to upstream, client: 192.0.2.1,
server: example.com, request: "GET / HTTP/1.1", upstream: "php-fpm"

upstream timed out (110: Connection timed out) while reading response header from upstream,
client: 192.0.2.1, upstream: "fastcgi://127.0.0.1:9000"

PHP-FPM Errors

WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

NOTICE: [pool www] child 1234 exited with code 0 after 300.051234 seconds from start

ERROR: unable to bind listening socket for address '127.0.0.1:9000': Address already in use (98)

Apache Errors (mod_proxy_fcgi)

(111)Connection refused: AH02454: FCGI: attempt to connect to Unix domain socket
/run/php-fpm/www.sock (*) failed

AH01079: failed to make connection to backend: 127.0.0.1

Error Characteristics → Root Cause Reference Table

Status Code Error Characteristic Root Cause
502 Connection refused PHP-FPM is not running, or the listen port does not match the nginx configuration
502 No such file or directory Using Unix sockets, but the path does not match the actual sock file of PHP-FPM
502 Permission denied The user running nginx lacks permission on the socket, or SELinux is blocking it
502 Prematurely closed / Connection reset PHP process crashed during execution (segfault, extension exception, or OOM kill)
502 Upstream sent too big header Response headers are too large (commonly due to excessive Set-Cookie), exceeding fastcgi buffer
503 No live upstreams All backends in the upstream block are unavailable
503 PHP-FPM max_children alert Concurrency exceeds the maximum number of child processes; new requests cannot be queued
503 No nginx errors Application layer actively returns this: e.g., WordPress upgrade .maintenance file remaining, rate limiting rules
504 Upstream timed out PHP execution time exceeds fastcgi_read_timeout (default is often 60s)
504 Only specific APIs time out External API calls without timeouts, slow database queries, or file lock waits

Troubleshooting Commands: Follow This Order

# ① Check if backend processes are running
systemctl status php-fpm
ss -lntp | grep -E '9000|php'
ps aux | grep -c '[p]hp-fpm'

# ② Check port/socket connectivity
nc -zv 127.0.0.1 9000
ls -l /run/php-fpm/www.sock

# ③ Real-time logs (most valuable, check both)
tail -f /var/log/nginx/error.log
tail -f /var/log/php-fpm/error.log

# ④ Bypass nginx to connect directly to php-fpm — determines if the issue is nginx or php
SCRIPT_NAME=/index.php 
SCRIPT_FILENAME=/var/www/html/index.php 
REQUEST_METHOD=GET 
cgi-fcgi -bind -connect 127.0.0.1:9000

# ⑤ Check if killed by OOM (essential when 502 occurs and processes disappear mysteriously)
dmesg -T | grep -iE 'oom|killed'
journalctl -k | grep -i oom

# ⑥ SELinux (when Permission denied appears)
getenforce
ausearch -m AVC -ts recent | head
setsebool -P httpd_can_network_connect 1

# ⑦ Disk space and inode usage (can cause mysterious 502s)
df -h && df -i

# ⑧ Average memory per single php-fpm process (to calculate max_children)
ps -o rss= -C php-fpm | awk '{s+=$1} END {print s/NR/1024 " MB"}'

Key Technique: Bypass Nginx to Connect Directly to PHP-FPM

When you cannot determine whether the issue lies in the nginx configuration or PHP itself, step ④ above is the fastest way to judge: send a request directly to php-fpm.

  • If HTML is returned normally → PHP side is fine; the fault lies in the nginx configuration (upstream address, socket path, permissions);
  • If connection fails or errors occur → The problem lies with php-fpm itself (not started, fully loaded, or processes crashed).

This step saves a significant amount of time spent guessing back and forth, especially when neither nginx nor php-fpm logs provide clear clues.

Configuration Modifications

Nginx (FastCGI Scenario)

upstream php-fpm {
    server 127.0.0.1:9000;
    # Or unix:/run/php-fpm/www.sock;
}

server {
    location ~ .php$ {
        include        fastcgi_params;
        fastcgi_pass   php-fpm;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_connect_timeout 60s;
        fastcgi_send_timeout    60s;
        fastcgi_read_timeout    300s;   # Main switch for 504
        fastcgi_buffering       on;
        fastcgi_buffer_size     32k;
        fastcgi_buffers        4 32k;   # Increase when encountering 502 too big header
    }
}

Nginx (Reverse Proxy Scenario, Parameter Names Differ)

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_connect_timeout 60s;
    proxy_read_timeout    300s;   # This is not fastcgi_read_timeout
    proxy_send_timeout    60s;
}

PHP-FPM Pool

[www]
listen       = 127.0.0.1:9000
listen.owner = nginx
listen.group = nginx
listen.mode  = 0660

pm                   = dynamic
pm.max_children      = 50      # Main switch for 503 / 502
pm.start_servers     = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests      = 500     # Prevent memory leak accumulation

request_terminate_timeout = 300s
request_slowlog_timeout   = 5s
slowlog                   = /var/log/php-fpm/www-slow.log
catch_workers_output      = yes

pm.max_children should not be chosen arbitrarily; estimate it using the formula below:

max_children ≈ Available Memory / Average Memory Usage per Single PHP-FPM Process

Decision Tree

Website reports 5xx
├─ 502
│  ├─ Connection refused      → PHP-FPM not started / Wrong port   → Start and verify listen
│  ├─ No such file or dir     → Socket path mismatch         → Align paths between php-fpm and nginx
│  ├─ Permission denied       → Socket permissions / SELinux     → Adjust listen.owner or setsebool
│  ├─ Prematurely closed      → PHP process crash              → Check PHP logs + dmesg OOM
│  └─ Sent too big header     → Response headers too large       → Increase fastcgi_buffer_size
├─ 503
│  ├─ No live upstreams       → All backends down              → Start backends / Check upstream definition
│  ├─ Max_children alert      → Concurrency maxed out          → Increase max_children or add rate limiting
│  └─ No nginx errors         → Application layer              → Check .maintenance, rate limiting rules
└─ 504
   ├─ Site-wide timeout       → PHP execution too long         → Increase read_timeout + Check slow logs
   └─ Specific API timeout    → Slow DB queries / External APIs→ Slow logs + Add timeouts to external calls

Scenario Walkthrough: Complete Troubleshooting for Intermittent 502

Below is a constructed typical scenario that strings together the commands into a complete chain. The focus is on why each step is taken, rather than just the conclusion.

Symptom: The site experiences intermittent 502 errors, occurring during afternoon traffic peaks and recovering automatically after a few minutes.

  1. Check nginx error logs → connect() failed (111: Connection refused) while connecting to upstream.
    The keyword is “refused” (connection refused) rather than “timeout” (time out), indicating that the backend was not responding on the port at that moment.
  2. Confirm if PHP-FPM is still alive → Processes are present, and ports are listening. It is alive, but connections are refused.
  3. Check memory → free -m shows very little remaining memory.
  4. Check kernel logs → dmesg | grep -i oom hits: OOM Killer terminated PHP-FPM child processes.

Root Cause: pm.max_children was calculated based on estimated single-process memory, but actual usage was higher. Under normal conditions, it was sufficient, but during peak hours, as the number of processes increased, it triggered OOM, causing child processes to be killed → 502; the process manager restarted them → self-healing.

Fix: Recalculate pm.max_children based on measured single-process usage (Available Memory ÷ Actual Single-Process Usage, leaving a 20% buffer), and add monitoring for memory levels.

Two Key Takeaways:

  • “Intermittent + Auto-recovery” almost always points to resource issues, not configuration errors. Configuration errors persist and do not fix themselves.
  • The scene of OOM is in dmesg, not in nginx logs. If you only look in error.log, you will never see the real culprit.

8 Common Pitfalls

  1. Modifying the wrong parameter name: fastcgi_read_timeout (for FastCGI) and proxy_read_timeout (for reverse proxy) are two different things; modifying the wrong one will have no effect.
  2. request_terminate_timeout smaller than fastcgi_read_timeout: PHP-FPM will kill the process first, and nginx receives a 502 instead of a 504, leading investigators in the completely wrong direction. The former should be ≥ the latter.
  3. max_children is not “the bigger, the better”: Setting it too high exhausts memory and triggers OOM, creating more 502s. Calculate single-process memory first before deciding.
  4. Only checking nginx logs: The root cause of 502s is mostly found in php-fpm logs; you must check both sides.
  5. Changes not taking effect: PHP-FPM requires systemctl reload php-fpm; use reload instead of restart to avoid cutting off currently processing requests.
  6. Users still see errors after backend recovery: CDN or reverse proxy cached the 502/503; you need to clear the cache or configure error responses to not be cached.
  7. WordPress upgrade interrupted: A residual .maintenance file causes the entire site to return 503; deleting it restores service, which is easily misdiagnosed as a server failure.
  8. Disk or inode full: Manifests as mysterious 502s; check both df -h and df -i; checking only one might miss the issue.

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 peers, provided solely for reference of real feedback, not fictional tickets from this site):

b****4 Rating: 5.0 2025-06-23 16:57 b****4 Rating: 5.0 2025-06-23 16:56 Jian****Wei Rating: 5.0 2021-01-20 15:03 Technology is awesome, speed is fast! Originally caused by a trojan resulting in Baidu global hijacking!!!!!! f****u Rating: 5.0 2021-01-02 20:43 Thanks for assisting in maintaining Yuncai’s normal operation. 1****1 Rating: 5.0 2020-11-20 10:03 Consistently good service 1****1 Rating: 5.0 2020-11-17 09:13 Thanks for the consistently good service. 1****1 Rating: 5.0 2020-09-25 15:42 Many thanks. 1****1 Rating: 5.0 2020-08-24 15:34 Many thanks to your company’s technical staff 1****1 Rating: 5.0 2020-07-24 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 exactly when needed, handled quickly 10***49 2022-04-12 5.0 On-time delivery | Affordable price | Skilled technology Needed rectification, configuration was fast, not bad

FREE CHECKUP

Free server checkup

We will send a problem checklist and remediation advice within one business day — no obligation to engage.

135 410 16684
Weekdays Mon – Fri 10:00 – 22:00 (UTC+8) · 7×24 emergency response
Call now
CONTACT

Contact Us

How can we help?

* Required