Fix Nginx 502 Bad Gateway: Root Causes and Minimal Checks

Topic: nginx-502-bad-gateway-upstream-errorUpdated 7/14/2026

Quick Answer

  • Conclusion: Nginx 502 Bad Gateway means Nginx (the reverse proxy) cannot establish a valid connection to the upstream service (PHP-FPM, Node.js, Gunicorn, etc.). The fix requires identifying whether the issue is a stopped upstream, socket/port mismatch, permission denial, buffer overflow, or resource exhaustion.
  • First checks: Run systemctl status php-fpm (or your upstream service) to confirm it's running, then check Nginx error logs at /var/log/nginx/error.log for the exact error message.
  • Minimal fix: Ensure the fastcgi_pass or proxy_pass directive in your Nginx config matches the upstream's listen address exactly. For PHP-FPM, verify both point to the same socket path (e.g., unix:/run/php-fpm/www.sock) or TCP address (e.g., 127.0.0.1:9000).
  • Applicable environment: Any Linux server running Nginx as a reverse proxy, especially with PHP-FPM, Node.js, Python (Gunicorn/uWSGI), or other application servers. This guide covers single-server deployments; containerized or clustered environments require additional considerations.

What Problem It Solves

The HTTP 502 Bad Gateway error is one of the most common and frustrating issues in web server administration. It occurs when Nginx, acting as a reverse proxy or gateway, sends a request to an upstream server but receives an invalid response or no response at all. This guide provides a systematic, step-by-step approach to diagnosing and resolving every common cause of this error, from misconfigured sockets to resource exhaustion.

Root Cause Analysis

Every 502 error originates from one of these fundamental problems:

  1. Upstream service is not running – The application server (PHP-FPM, Node.js, etc.) has stopped or crashed.
  2. Socket or port mismatch – Nginx is configured to connect to one address, but the upstream is listening on a different one.
  3. Permission denied – The Nginx user cannot read/write the Unix socket file.
  4. Connection refused – The upstream is running but not accepting connections on the expected interface/port.
  5. Response header too large – The upstream sent headers exceeding Nginx's default buffer size.
  6. Worker pool exhausted – All upstream workers are busy, and the request queue is full.

The error log at /var/log/nginx/error.log is your primary diagnostic tool. Each error message maps directly to one of these root causes.

Common Errors and Fixes

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

Root cause: The PHP-FPM service is not running, or the socket path in Nginx does not match PHP-FPM's configured listen directive.

Fix:

BASH
# Check if PHP-FPM is running
systemctl status php-fpm

# If not running, start it
systemctl start php-fpm

# Verify the socket path in PHP-FPM config
grep '^listen' /etc/php-fpm.d/www.conf
# Example output: listen = /run/php-fpm/www.sock

# Verify the same path in Nginx config
grep 'fastcgi_pass' /etc/nginx/conf.d/your-site.conf
# Example output: fastcgi_pass unix:/run/php-fpm/www.sock;

Both paths must be identical. If they differ, update the Nginx configuration to match.

Error: connect() failed (111: Connection refused)

Root cause: The upstream service is running but not listening on the expected IP and port combination, or a firewall/SELinux is blocking the connection.

Fix:

BASH
# Check what the upstream is actually listening on
ss -tlnp | grep 9000
# Or for a specific process
ss -tlnp | grep php-fpm

# If the upstream is bound to 127.0.0.1:9000 but Nginx connects to 0.0.0.0:9000, fix the upstream config
# For PHP-FPM, edit /etc/php-fpm.d/www.conf:
# listen = 127.0.0.1:9000

# Check firewall rules
iptables -L -n | grep 9000

# If SELinux is blocking, check and enable network connections
getsebool httpd_can_network_connect
setsebool -P httpd_can_network_connect 1

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

Root cause: The Nginx user (typically nginx or www-data) does not have read/write permission on the PHP-FPM socket file.

Fix:

BASH
# Check socket file permissions
ls -la /run/php-fpm/www.sock
# Example: srw-rw---- 1 root www-data 0 ...

# Add the Nginx user to the socket's group
usermod -aG www-data nginx

# Or change the socket owner/group in PHP-FPM config
# Edit /etc/php-fpm.d/www.conf:
# listen.owner = nginx
# listen.group = nginx
# listen.mode = 0660

# Restart both services
systemctl restart php-fpm nginx

# Check SELinux if still failing
ausearch -m avc -ts recent

Error: upstream sent too big header while reading response header from upstream

Root cause: The upstream application sent HTTP response headers (cookies, custom headers) larger than Nginx's default buffer size (usually 4KB or 8KB).

Fix: Increase buffer sizes in the Nginx configuration for the affected location block.

For FastCGI (PHP-FPM):

NGINX
location ~ \.php$ {
    fastcgi_pass unix:/run/php-fpm/www.sock;
    fastcgi_buffer_size 32k;
    fastcgi_buffers 8 32k;
    fastcgi_busy_buffers_size 64k;
    fastcgi_temp_file_write_size 64k;
    # ... other fastcgi params
}

For generic proxy (Node.js, Python, etc.):

NGINX
location /api/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_buffer_size 32k;
    proxy_buffers 8 32k;
    proxy_busy_buffers_size 64k;
    # ... other proxy params
}

After updating, test and reload:

BASH
nginx -t && systemctl reload nginx

Error: Intermittent 502 errors that resolve on refresh

Root cause: PHP-FPM worker pool exhaustion. All pm.max_children workers are busy, and the request queue is full.

Fix: Calculate and increase pm.max_children based on available memory.

BASH
# Check current PHP-FPM pool settings
grep -E '^pm\.(max_children|start_servers|min_spare_servers|max_spare_servers|max_requests)' /etc/php-fpm.d/www.conf

# Calculate max_children: (Total RAM - OS/other services) / Average PHP process memory
# Example: 8GB RAM, 2GB for OS, average PHP process = 50MB
# max_children = (8192 - 2048) / 50 ≈ 122

# Edit /etc/php-fpm.d/www.conf
pm = dynamic
pm.max_children = 122
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 30
pm.max_requests = 500

# Restart PHP-FPM
systemctl restart php-fpm

Production Notes and Security Checks

Dedicated User Isolation

Never run Nginx and PHP-FPM as the same user. Create a dedicated system user for each application:

BASH
# Create a dedicated user for the application
useradd -r -s /sbin/nologin -M myapp

# Configure PHP-FPM to run as this user
# In /etc/php-fpm.d/www.conf:
user = myapp
group = myapp
listen.owner = nginx
listen.group = nginx
listen.mode = 0660

# Add nginx user to the application group
usermod -aG myapp nginx

SELinux Best Practices

If SELinux is enforcing (check with getenforce), you must configure the appropriate booleans:

BASH
# For Unix socket connections (PHP-FPM)
setsebool -P httpd_can_network_connect 1

# For TCP connections to upstream services
setsebool -P httpd_can_network_connect 1

# Check SELinux denials
ausearch -m avc -ts recent | audit2why

Monitoring for Proactive Detection

To catch 502 errors before users report them, monitor Nginx error logs and upstream health:

BASH
# Count 502 errors in the last 5 minutes
tail -5000 /var/log/nginx/error.log | grep "502" | wc -l

# Monitor PHP-FPM pool status (enable pm.status_path in www.conf)
curl http://127.0.0.1/status?plain

FAQ

Q: My site gets 502 errors intermittently, but a refresh fixes it. What's happening?

A: This is almost always PHP-FPM worker pool exhaustion. When all pm.max_children workers are busy processing requests, new requests queue up. If the queue fills, Nginx returns 502. Fix: Increase pm.max_children based on available memory, or switch to pm = dynamic mode so PHP-FPM adjusts workers automatically based on load.

Q: I've checked everything in this guide, but 502 errors persist. What else could it be?

A: Several less common causes: 1) Upstream application crashes – check the application's own logs (e.g., Node.js stdout/stderr, Python logs). 2) Resource exhaustion – the OS may kill upstream processes when memory or CPU is critically low. 3) DNS resolution failure – if proxy_pass uses a domain name, Nginx may fail to resolve it. 4) Nginx configuration syntax error – run nginx -t to validate. 5) Caching issues – if using Nginx cache, try clearing it with rm -rf /var/cache/nginx/*.

Q: How do I debug 502 errors in Docker containers?

A: Docker adds complexity. Follow these steps: 1) Check container status: docker ps -a. 2) Ensure both containers are on the same Docker network: docker network ls and docker network inspect <network>. 3) For TCP connections, verify the upstream container's port is correctly exposed and not remapped. 4) For Unix sockets, ensure the socket directory is shared via a volumes mount in both containers. 5) View container logs: docker logs <container_name> for both Nginx and the upstream service.

Related Guides