A 504 Gateway Timeout error means a gateway server did not receive a response from an upstream server within the allowed time. This guide covers every cause — from slow database queries to misconfigured timeouts — and provides targeted fixes.
A 504 error follows a specific sequence: a client sends a request to a gateway (Nginx, a CDN, or a load balancer), the gateway forwards it to an upstream server, and the upstream server takes too long to respond. The gateway's timeout expires and it returns 504 to the client.
| Root cause | Where it originates | Fix |
|---|---|---|
| Slow database query | Database layer | Add indexes, optimize queries, add caching |
| Nginx proxy_read_timeout too short | Nginx configuration | Increase timeout values |
| PHP max_execution_time too short | PHP configuration | Increase execution time limit |
| External API call taking too long | Application code | Add async processing or increase timeout |
| Server under heavy load | Server resources | Scale up or optimize resource usage |
| Network latency between gateway and upstream | Network/infrastructure | Move services closer or use faster networking |
# Check Nginx error log for timeout messages
sudo grep "upstream timed out" /var/log/nginx/error.log | tail -20
# Check server load
uptime && free -h
# Check slow MySQL queries (if using MySQL)
sudo mysql -e "SHOW PROCESSLIST;" | grep -v Sleep
# Check slow query log (if enabled)
sudo tail -50 /var/log/mysql/mysql-slow.logNginx has several timeout directives that control how long it waits for upstream responses. Increase them to match your application's expected processing time:
http {
# How long to wait for upstream to accept a connection
proxy_connect_timeout 60s;
# How long to wait for upstream to send data
proxy_send_timeout 120s;
# How long to wait for upstream to respond (most important)
proxy_read_timeout 300s;
# For PHP-FPM via FastCGI:
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 120s;
fastcgi_read_timeout 300s;
}sudo nginx -t && sudo systemctl reload nginxSlow database queries are the most common cause of 504 errors in production applications. Enable the slow query log to identify problematic queries:
# In /etc/mysql/mysql.conf.d/mysqld.cnf:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2 # Log queries taking > 2 seconds
# Restart MySQL
sudo systemctl restart mysql# Use EXPLAIN to see query execution plan
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
# Add an index if missing
ALTER TABLE orders ADD INDEX idx_user_id (user_id);
# Check existing indexes
SHOW INDEX FROM orders;EXPLAIN to identify queries doing full table scans (type: ALL in the output) — these are the best candidates for indexing.PHP has a max_execution_time setting that terminates scripts running too long. If this is shorter than Nginx's timeout, PHP will terminate the script before Nginx times out, causing a 504:
; Increase PHP execution time limit (in seconds, 0 = unlimited)
max_execution_time = 300
; Also increase input time for large uploads
max_input_time = 300sudo systemctl restart php8.2-fpmIf a CDN or load balancer sits in front of your server, it has its own timeout settings that may be shorter than your server's timeouts. Common CDN timeout defaults:
| Provider | Default timeout | How to increase |
|---|---|---|
| Cloudflare (free) | 100 seconds | Upgrade to Pro/Business for longer timeouts |
| AWS ALB | 60 seconds | Modify idle timeout in load balancer settings |
| AWS CloudFront | 30 seconds | Increase origin response timeout in distribution settings |
| Nginx (reverse proxy) | Configurable | Set proxy_read_timeout in nginx.conf |
For long-running operations (report generation, bulk imports, external API calls), the best fix is to move the work out of the synchronous request-response cycle:
Alive24x7 monitors both uptime and response time. Get alerted when your site returns a 504 error or when response times exceed your threshold — before users start complaining.
Start Free Monitoring