Troubleshooting Nginx 504 Gateway Timeout: Upstream Connection Timed Out

Resolve Nginx 504 Gateway Timeout errors caused by upstream connection issues. This expert guide details root causes and provides step-by-step fixes for web server performance.


When users encounter a “504 Gateway Timeout” error on your Nginx-powered website, it’s a critical signal that Nginx, acting as a reverse proxy, failed to receive a timely response from an upstream server. This typically indicates a bottleneck or failure in the backend application serving the request. As a seasoned Systems Administrator, diagnosing and resolving this issue requires a systematic approach, diving deep into Nginx, application server, and system-level configurations and logs.

Symptom & Error Signature

Users attempting to access your website will see a generic “504 Gateway Timeout” page in their browser. This page is often styled by Nginx or the server’s default error page configuration.

Simultaneously, the Nginx error logs on your server will record the specific nature of the timeout. You can typically find these logs at /var/log/nginx/error.log.

Browser Output Example:

504 Gateway Timeout

The gateway did not receive a timely response from the upstream server or application.

Nginx Error Log Signature:

2026/06/27 10:30:45 [error] 12345#12345: *6789 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 192.168.1.100, server: example.com, request: "GET /long-running-task HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:", host: "example.com"

2026/06/27 10:31:02 [warn] 12346#12346: *6790 a client request body is buffered to a temporary file /var/cache/nginx/client_temp/0000000001, client: 192.168.1.101, server: api.example.com, request: "POST /data-upload HTTP/1.1", upstream: "http://127.0.0.1:8080/data-upload", host: "api.example.com"

The key phrases to look for are upstream timed out or upstream connection timed out followed by the specific upstream target (e.g., fastcgi://... or http://...). The error code 110: Connection timed out is a common symptom.

Root Cause Analysis

A 504 Gateway Timeout indicates that Nginx, acting as a proxy, did not receive a response from the backend (upstream) server within a configured timeout period. Nginx doesn’t generate the content itself; it merely passes requests to a backend process (like PHP-FPM, Gunicorn, Node.js, Tomcat, etc.) and expects a response.

The primary reasons for an Nginx 504 error, particularly with the “upstream connection timed out” message, include:

  1. Long-Running Application Processes: The most common cause. Your backend application might be executing a script or query that takes longer than the default Nginx or application server timeouts allow. This could be due to:
    • Complex database queries.
    • External API calls with high latency or timeouts.
    • Heavy computations or data processing.
    • Large file uploads/downloads taking too long to process.
  2. Upstream Server Unavailability or Crash: The backend application server (e.g., PHP-FPM, Gunicorn, Node.js process) might have crashed, be overloaded, or simply not be running, causing Nginx to wait indefinitely for a connection that never establishes or responds.
  3. Resource Exhaustion on Upstream Server: The upstream server might be experiencing high CPU, memory, or I/O load, making it unresponsive. This is common when the server cannot handle the current traffic volume or specific resource-intensive requests.
  4. Misconfigured Timeouts: Nginx’s proxy_read_timeout, fastcgi_read_timeout, uwsgi_read_timeout, etc., might be set too low for the expected application response times. Similarly, the backend application server might have its own request execution timeouts (e.g., request_terminate_timeout in PHP-FPM, timeout in Gunicorn) that are shorter than Nginx’s timeout, leading to the application process being killed before Nginx receives a response.
  5. Network Issues: Although less common for “upstream timed out” within a single server, network latency or packet loss between Nginx and a backend server (especially in a multi-server setup or Docker network) can lead to timeouts.
  6. Deadlocks or Infinite Loops: An application bug might cause a process to enter a deadlock or an infinite loop, consuming resources and never returning a response.

Step-by-Step Resolution

Follow these steps systematically to identify and resolve the 504 Gateway Timeout issue.

1. Identify the Specific Upstream and Check its Logs

First, pinpoint which backend application Nginx is attempting to proxy to. The Nginx error log message (e.g., upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:" or upstream: "http://127.0.0.1:8080") will tell you.

Then, immediately check the logs of that specific upstream application server.

  • For PHP-FPM:
    sudo tail -f /var/log/php8.1-fpm.log  # Or check specific pool logs
    # or systemd journal
    sudo journalctl -u php8.1-fpm -f
    Look for errors, warnings, or processes terminating. PHP-FPM often logs “script timed out” messages if request_terminate_timeout is hit.
  • For Gunicorn/UWSGI (Python apps): Check the application’s stderr or configured log file.
  • For Node.js apps: Check stdout/stderr of the Node.js process, or the log file configured in pm2 or your application.
  • For Docker containers:
    docker logs <container_name_or_id>
    If using Docker Compose:
    docker compose logs -f <service_name>

[!IMPORTANT] The upstream application’s logs are critical. They often reveal the true bottleneck (e.g., a slow database query, external API call, or a resource-intensive script) that Nginx only reports as a timeout.

2. Monitor System Resources

While the timeout is occurring, check the server’s resource utilization. High CPU, memory, or I/O can cause any application to become unresponsive.

top             # General system overview
htop            # Interactive process viewer (install with: sudo apt install htop)
free -h         # Check memory usage
df -h           # Check disk space
iotop           # Check disk I/O (install with: sudo apt install iotop)

Look for processes consuming excessive resources, especially those related to your backend application or database.

3. Adjust Nginx Proxy Timeouts

If your application genuinely needs more time to process requests, you’ll need to increase Nginx’s timeout values. These should be set in your Nginx configuration, typically within the http, server, or location block.

[!WARNING] Indiscriminately increasing timeouts can mask underlying performance issues and make your server more vulnerable to slow Loris attacks or resource exhaustion. Always investigate the root cause first.

Common Nginx Timeout Directives:

  • proxy_connect_timeout: Defines a timeout for establishing a connection with a proxied server.
  • proxy_send_timeout: Sets a timeout for transmitting a request to the proxied server.
  • proxy_read_timeout: Sets a timeout for reading a response from the proxied server. This is the most common one for 504s.

For PHP-FPM (using fastcgi_pass):

  • fastcgi_connect_timeout: Timeout for connecting to the FastCGI server.
  • fastcgi_send_timeout: Timeout for sending a request to the FastCGI server.
  • fastcgi_read_timeout: Timeout for reading a response from the FastCGI server. This is the most common one for 504s with PHP-FPM.

Example Nginx Configuration (/etc/nginx/sites-available/your_site.conf):

server {
    listen 80;
    server_name example.com;

    location / {
        # For HTTP proxied backends (e.g., Node.js, Gunicorn)
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Increase proxy timeouts to 300 seconds (5 minutes)
        proxy_connect_timeout 300s;
        proxy_send_timeout 300s;
        proxy_read_timeout 300s;
    }

    location ~ \.php$ {
        # For PHP-FPM backends
        include snippets/fastcgi-php.conf; # This often includes basic fastcgi_params
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;

        # Increase FastCGI timeouts to 300 seconds (5 minutes)
        fastcgi_connect_timeout 300s;
        fastcgi_send_timeout 300s;
        fastcgi_read_timeout 300s;
    }
}

After modifying the Nginx configuration, always test and reload:

sudo nginx -t
sudo systemctl reload nginx

4. Adjust Upstream Application Server Timeouts

It’s crucial that your application server’s timeouts are at least as long as Nginx’s, or preferably slightly longer, so that the application has a chance to complete before Nginx cuts off the connection.

  • For PHP-FPM: Edit the PHP-FPM pool configuration file (e.g., /etc/php/8.1/fpm/pool.d/www.conf).
    ; Set the timeout for a request to finish.
    ; '0' means 'no timeout'.
    request_terminate_timeout = 300
    Also, check php.ini (/etc/php/8.1/fpm/php.ini):
    max_execution_time = 300
    max_input_time = 300
    Restart PHP-FPM after changes:
    sudo systemctl restart php8.1-fpm
  • For Gunicorn: Modify your Gunicorn configuration (e.g., gunicorn_config.py or command-line args):
    # Set the maximum number of seconds to wait for a worker to respond to requests
    timeout = 300
    Restart Gunicorn.
  • For Node.js (e.g., Express.js): If your Node.js application handles HTTP requests directly, you might need to adjust the server’s timeout:
    const server = app.listen(port, () => {
      console.log(`Server listening on port ${port}`);
    });
    server.timeout = 300000; // 5 minutes in milliseconds
    Restart your Node.js application.

5. Optimize Application Code and Database Queries

If increasing timeouts only postpones the problem, the true fix lies in optimizing your application.

  • Profile your application: Use tools specific to your language (e.g., Xdebug for PHP, cProfile for Python, Node.js profilers) to identify slow functions.
  • Optimize database queries:
    • Add appropriate indexes.
    • Refactor complex queries.
    • Cache frequently accessed data.
    • Use EXPLAIN or similar tools to analyze query plans.
  • Reduce external API calls: Cache responses, implement asynchronous processing if possible, or reduce the number of calls.
  • Process large tasks asynchronously: For long-running operations (e.g., image processing, report generation, bulk imports), offload them to a background job queue (e.g., Redis Queue, RabbitMQ, Celery) to be processed by workers, allowing the web request to respond quickly.

6. Verify Upstream Server Status and Health

Ensure the upstream server process is running and healthy.

# For PHP-FPM
sudo systemctl status php8.1-fpm

# For Docker containers
docker ps -a
docker inspect <container_id> # check health status

If the upstream process is frequently crashing, check its specific logs for crash reasons. This could be due to memory limits, unhandled exceptions, or segmentation faults.

7. Docker-Specific Considerations

If your upstream application is running in Docker containers, consider these points:

  • Resource Limits: Ensure your Docker container has sufficient CPU and memory allocated. By default, containers can consume all host resources, but if limits are set too low, the application can starve. Example docker-compose.yml:

    services:
      app:
        image: your_app_image
        deploy:
          resources:
            limits:
              cpus: '1.0'
              memory: 1G
            reservations:
              cpus: '0.5'
              memory: 512M
  • Network Configuration: Verify that Nginx can communicate with the Docker container’s exposed port.

    docker inspect <container_id> | grep "IPAddress"

    Ensure Nginx proxy_pass or fastcgi_pass directives point to the correct IP or service name within the Docker network.

  • Health Checks: Implement Docker health checks for your application containers. This allows Docker to automatically restart unhealthy containers, improving reliability.

    services:
      app:
        image: your_app_image
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
          interval: 30s
          timeout: 10s
          retries: 3

By systematically working through these steps, starting with log analysis and resource monitoring, you can effectively diagnose and resolve the Nginx 504 Gateway Timeout issue.