HTTP 504 Gateway Timeout: Causes and Solutions for Sysadmins
The 504 Gateway Timeout error happens when a proxy (nginx, Cloudflare) waits for an upstream response longer than its timeout allows. Unlike 502 (invalid response), 504 is expiry of a wait. Let us cover the causes, how to configure timeouts correctly, and how to optimize slow requests instead of just hiding them.
What 504 Means
Per RFC 9110 §15.6.5, 504 means the server, acting as a gateway, did not get a timely response from upstream. The key word is "timely" — the timeout is configured on the proxy.
6 Common Causes
- Slow SQL query without an index, blocking a transaction.
- Slow external API документацию that depends on a third party.
- Suboptimal code — N+1 queries, un-массовую проверку URL operations.
- Heavy work inside the request/response cycle (PDF generation, sending emails).
- Low timeout in nginx/Cloudflare for legitimately long operations.
- Upstream stuck — database deadlock, blocked thread.
Diagnosing Slow Requests
# Top slow requests in access.log
awk '$10 > 5' /var/log/nginx/access.log | head -20
# MySQL slow log
mysqldumpslow -t 10 /var/log/mysql/slow.log
# PHP-FPM slow log
# /etc/php/8.4/fpm/pool.d/www.conf:
# slowlog = /var/log/php/www-slow.log
# request_slowlog_timeout = 5s
tail -100 /var/log/php/www-slow.log
# Node.js: event loop lag
// npm install clinic
// clinic doctor -- node app.jsCheck external response time via Enterno.io PageSpeed Check — get TTFB, Web Vitals, and bottlenecks.
Proper nginx Timeout Configuration
http {
# Connection to upstream
proxy_connect_timeout 10s;
# Sending request upstream
proxy_send_timeout 30s;
# Reading upstream response
proxy_read_timeout 60s;
# For FastCGI (PHP-FPM)
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 30s;
fastcgi_read_timeout 60s;
}
# Long-polling endpoint — dedicated location
location /api/long-poll {
proxy_read_timeout 300s; # 5 minutes
proxy_pass http://backend;
}PHP-FPM: max_execution_time
# php.ini
max_execution_time = 30
max_input_time = 60
# For large data exports:
# Set per-request via ini_set()
ini_set('max_execution_time', 300); # 5 minutes
set_time_limit(300);
# But better — move to a queue!Node.js: Server Timeout
const server = app.listen(3000);
server.setTimeout(60000); // 60 seconds
server.keepAliveTimeout = 61000;
server.headersTimeout = 65000; // must be > keepAliveTimeout
// For Fastify
const app = Fastify({
connectionTimeout: 60000,
keepAliveTimeout: 61000,
});Right Solution: Offload to Background
Raising timeouts forever is an anti-pattern. The right solution is offloading long operations to a queue.
// Bad: blocks the request
app.post('/generate-report', async (req, res) => {
const pdf = await generateBigPDF(req.body); // 3 minutes
await sendEmail(pdf);
res.json({ok: true});
});
// Good: queue + notification
app.post('/generate-report', async (req, res) => {
const jobId = await queue.add('generate-report', req.body);
res.status(202).json({jobId, status: 'queued'});
});
// Worker processes in background
queue.process('generate-report', async (job) => {
const pdf = await generateBigPDF(job.data);
await sendEmail(pdf);
});The client receives 202 Accepted + jobId and polls /jobs/:id or gets a WebSocket/webhook notification.
Optimizing Slow DB Queries
-- Find long queries
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;
-- EXPLAIN a query plan
EXPLAIN SELECT * FROM orders WHERE user_id = 1 ORDER BY created_at DESC LIMIT 10;
-- Add an index if needed
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC);
-- Check table sizes
SELECT table_name, ROUND(data_length/1024/1024) AS mb
FROM information_schema.tables
WHERE table_schema = 'your_db'
ORDER BY data_length DESC LIMIT 10;Cloudflare 504 — Specifics
Cloudflare has a hard 100-second limit on free/pro plans. Options:
- Use the Enterprise plan (up to 6000 seconds).
- Route long endpoints via Origin bypass on a separate subdomain without CF proxy.
- Optimize code below 100s (the right approach).
Frequently Asked Questions
Q: How does 504 differ from 502?
A: 504 — upstream did not respond in time. 502 — upstream responded invalidly or closed the connection.
Q: What timeout is adequate?
A: Web requests: 30-60s. APIs: 10-30s. Long-polling: 300+s. Long-running tasks: move to a queue.
Q: How to detect 504 automatically?
A: Enterno.io Monitors with short timeouts trigger alerts. Also add APM (Sentry, New Relic).
Q: Does 504 affect SEO?
A: Yes, critically. Googlebot has its own timeout (~30s). Systematic 504s cause deindexing.
Conclusion
504 is not a timeout bug — it is a symptom of slow code or a slow external API. Monitor the slow log, optimize queries, offload long work to a queue. Set timeouts generously but not infinitely. Hook up Enterno.io to automatically catch 504s across regions.
Check your website right now
Check now →