504 Gateway Time-out: What It Means & How to Fix It
Key takeaway
A 504 Gateway Time-out means a proxy or gateway (nginx, Cloudflare, a load balancer, a CDN) waited for the server behind it and gave up: the upstream didn't answer in time. As a visitor, wait a minute and reload; the fix is the site's. As the owner, find the slow part (a query, an external API, busy PHP workers) in the logs, and check each layer's timeout: nginx waits 60 seconds by default, CloudFront 30, Google Cloud's load balancer 30, and Cloudflare 125 before it shows Error 524.
Check it now

Start reading
- What Is a 504 Gateway Timeout?
- What a 504 Error Looks Like
- How a 504 Gateway Timeout Happens
- Common Causes of 504 Gateway Timeout
- Fix for Visitors: What You Can Do
- Fix 1: Increase Timeout Settings (Nginx & Apache)
- Fix 2: Optimize Slow Scripts and Database Queries
- Fix 3: Check Server Resources (CPU, RAM, Disk)
- Fix 4: Check Error Logs
- Fix 5: Adjust PHP-FPM Settings
- Fix 6: Check CDN and Proxy Configuration
- Fix 7: WordPress-Specific Solutions
- 504 vs 502 vs 503 vs 408: What Is the Difference?
- Does a 504 Error Affect SEO?
- How to Prevent 504 Gateway Timeout Errors
- Frequently Asked Questions
What Is a 504 Gateway Timeout?
A 504 Gateway Timeout is an HTTP status code that means a server acting as a gateway or proxy did not receive a timely response from an upstream server. The proxy waited for the upstream to respond, but it took too long, so the proxy gave up and returned a 504 to your browser.
RFC 9110 defines it: "The 504 (Gateway Timeout) status code indicates that the server, while acting as a gateway or proxy, did not receive a timely response from an upstream server it needed to access in order to complete the request" (RFC 9110 §15.6.5).
The key word is gateway. A 504 always involves at least two servers: the one you connected to (the proxy/gateway) and the one behind it (the upstream/origin) that failed to respond. Common proxies include Nginx reverse proxy, Cloudflare, AWS Application Load Balancer (ALB), and CloudFront.
Is it 504 for everyone, or just you? Check it
What a 504 Error Looks Like
The wording depends on which layer gave up:
- 504 Gateway Time-out with "nginx" underneath — nginx (it spells it with a hyphen)
- 504 Gateway Time-out · The server didn't respond in time. — HAProxy's default page
- Gateway Timeout · The gateway did not receive a timely response from the upstream server or application. — Apache in front of PHP-FPM (mod_proxy_fcgi). Apache proxying an HTTP backend shows Proxy Error · Error reading from remote server (a 502) instead.
- ERROR · The request could not be satisfied · 504 ERROR — Amazon CloudFront
- Error 524: A timeout occurred — Cloudflare's version: it reached your server, but the response didn't arrive in time
- This page isn't working · example.com took too long to respond. · HTTP ERROR 504 — Chrome, when the 504 has no page of its own
Whatever the wording, the cause is the same: a proxy waited for the server behind it, and the answer didn't come in time. (Chrome uses the same "took too long to respond" line when your browser couldn't connect at all, but then the heading is "This site can't be reached" and the code is ERR_CONNECTION_TIMED_OUT, not HTTP ERROR 504: see ERR_CONNECTION_TIMED_OUT.)
How a 504 Gateway Timeout Happens
To understand the 504 error, you need to understand the timeout chain between your browser and the origin server. A typical web request passes through multiple layers, and each layer has its own timeout setting.
Here is a typical request flow: Browser → CDN (Cloudflare) → Load Balancer → Nginx → PHP-FPM → Database. If the database query takes 90 seconds and nginx's fastcgi_read_timeout is 60 seconds, nginx stops waiting and returns a 504 to the load balancer, which passes it back through the CDN to your browser.
The server that returns the 504 is usually a proxy in the middle, not the application itself. The application may still be working on the request, or it may be stuck.
| Layer | Default timeout | What happens when it runs out |
|---|---|---|
| Cloudflare (Free, Pro, Business) | 125 seconds | Error 524 (Cloudflare's own code) |
| Amazon CloudFront | 30 seconds (1-120 s; more on request) | 504 ERROR |
| AWS Application Load Balancer | 60 seconds idle | 504 from awselb |
| Google Cloud load balancer | 30 seconds | 502 on the classic and global external load balancers; 504 on regional and internal ones |
| nginx (proxy_read_timeout, fastcgi_read_timeout) | 60 seconds | 504 Gateway Time-out |
| Apache (ProxyTimeout) | Same as Timeout: 60 seconds | 504 with PHP-FPM (mod_proxy_fcgi); an HTTP backend gives 502 Proxy Error |
| PHP-FPM (request_terminate_timeout) | 0 (off) | Worker killed: nginx gets a closed connection (502) |
Sources: Cloudflare 524, CloudFront origin settings, Google Cloud, and each server's docs. PHP's own max_execution_time (30 seconds) doesn't give a 504: a script that hits it stops with a fatal error, which shows as a 500. And on Linux it doesn't count time spent waiting for the database or other I/O, so a script stuck on a slow query can run far longer than it.
Common Causes of 504 Gateway Timeout
The usual reasons a proxy gives up waiting:
- A slow request — a heavy database query, a report, or a call to a slow third-party API takes longer than the proxy's timeout.
- An overloaded server — CPU at 100%, memory pressure, or every PHP-FPM worker busy, so new requests wait in a queue until the proxy gives up.
- Database bottlenecks — slow queries, missing indexes, locked tables or an exhausted connection pool.
- Timeouts set too low — nginx's 60 seconds is too short for a backend that legitimately needs longer (an export, an import, a big upload).
- Network trouble between proxy and origin — packet loss or a firewall that silently drops the proxy's packets (a firewall that rejects them gives 502 instead).
- A CDN's fixed limit — Cloudflare waits 125 seconds on Free, Pro and Business, whatever your nginx allows, then shows Error 524.
- A traffic flood — a spike or an attack ties up the workers, so ordinary requests aren't answered in time. (A server that knows it's overloaded can answer 503 instead.)
Fix for Visitors: What You Can Do
If you see a 504 error on someone else's website, the problem is on their server — not your device. However, there are a few things worth trying.
- Wait a minute and reload — many 504s last only as long as a busy moment on the server.
- Check whether it's down for everyone — the Website Down Checker opens the page from 11 places. If they get 504 too, it's the site.
- Try a different network — mobile data instead of Wi-Fi, or without a VPN, in case your own proxy or VPN is the gateway that's timing out.
- Check the site's status page or social accounts — busy sites often post about outages.
Fix 1: Increase Timeout Settings (Nginx & Apache)
The most common fix for 504 errors is increasing the timeout values on your reverse proxy. If your backend legitimately needs more than 60 seconds (the default), the proxy needs to know to wait longer.
# nginx — reverse proxy to a backend (Node.js, Python, etc.)
location / {
proxy_pass http://backend;
proxy_read_timeout 300;
proxy_send_timeout 300;
}
# nginx — FastCGI (PHP-FPM)
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
include fastcgi_params;
}
# Leave proxy_connect_timeout / fastcgi_connect_timeout at their defaults:
# nginx caps them at about 75 seconds, and a dead backend should fail fast.For Apache, add ProxyTimeout 300 in your VirtualHost or use ProxyPass / http://backend:8080/ timeout=300 for one backend.
Important: the read and send timeouts measure the gap between two successive read or write operations, not the total transfer time. So proxy_read_timeout 300 means "if no data arrives for 300 seconds", not "the whole response must finish in 300 seconds". Reload after changing them: sudo nginx -t && sudo systemctl reload nginx.
Behind a CDN, its own limit still applies: Cloudflare cuts at 125 seconds (Free to Business) and CloudFront at 30 by default, so raising nginx past them changes nothing for visitors who come through the CDN.
Fix 2: Optimize Slow Scripts and Database Queries
If your backend consistently exceeds the timeout, increasing the timeout value only masks the problem. The real fix is making the backend respond faster.
- Find slow queries — Enable MySQL slow query log (
slow_query_log = 1,long_query_time = 1) or useEXPLAIN ANALYZEon suspect queries. Add missing indexes, avoidSELECT *, and paginate large result sets. - Add caching — Use Redis or Memcached to cache expensive query results. A query that takes 5 seconds on every page load should be cached.
- Move heavy work to background jobs — Report generation, email sending, image processing, and data imports should run in a job queue (Celery, Sidekiq, Bull), not in the HTTP request cycle.
- Optimize API calls — If your backend calls slow third-party APIs, add timeouts to those calls and implement circuit breakers so one slow API does not block all requests.
- Reduce N+1 queries — ORM-generated queries often make hundreds of individual database calls. Use eager loading or batch queries to reduce round trips.
Fix 3: Check Server Resources (CPU, RAM, Disk)
If the origin server is overloaded, it cannot process requests fast enough, and the proxy times out waiting. Check what is consuming resources.
# Check CPU and memory usage
top -bn1 | head -20
# Check disk space (full disk = silent failures)
df -h
# Check memory details
free -m
# Find processes using the most CPU
ps aux --sort=-%cpu | head -10
# Find processes using the most memory
ps aux --sort=-%mem | head -10
# Check active network connections
ss -sIf CPU or RAM is at 90%+, you need to either optimize your application, kill runaway processes, or upgrade your server. If disk space is full, clear old log files, backups, or temp files — a full disk can silently crash databases and cause cascading 504 errors.
Fix 4: Check Error Logs
Error logs tell you exactly why the proxy returned 504. Always check logs before guessing at the cause.
# Nginx error log (look for "upstream timed out")
tail -50 /var/log/nginx/error.log
# Apache error log
tail -50 /var/log/apache2/error.log # Debian/Ubuntu
tail -50 /var/log/httpd/error_log # CentOS/RHEL
# PHP-FPM log
tail -50 /var/log/php8.3-fpm.log
# System log (OOM kills, crashes)
tail -50 /var/log/syslogCommon log messages behind a 504:
"upstream timed out (110: Connection timed out) while reading response header from upstream" (nginx) — the backend took longer than proxy_read_timeout (or fastcgi_read_timeout). Speed it up, or raise the timeout if the wait is legitimate.
"upstream timed out (110: Connection timed out) while connecting to upstream" (nginx) — nginx couldn't even connect in time: a firewall dropping packets, or a backend too busy to accept connections.
"server reached pm.max_children setting" (PHP-FPM) — every worker is busy, so requests wait in the queue. Raise pm.max_children only if there's RAM for it; otherwise find the slow requests holding workers.
"Too many connections" (MySQL) — the connection limit is used up. New connections fail at once (a 500, such as WordPress's "Error establishing a database connection"), while the queries holding them are often the slow ones behind your 504s.
Fix 5: Adjust PHP-FPM Settings
For PHP apps (WordPress, Laravel, Magento), keep the timeouts in a chain, each layer slightly longer than the one behind it: nginx's fastcgi_read_timeout ≥ PHP-FPM's request_terminate_timeout ≥ PHP's max_execution_time.
| Setting | File | Default | Suggested |
|---|---|---|---|
| max_execution_time | php.ini | 30 seconds | What your slowest legitimate page needs (it doesn't count DB waits on Linux) |
| request_terminate_timeout | PHP-FPM pool config | 0 (off) | A little above max_execution_time, as a hard stop |
| pm.max_children | PHP-FPM pool config | 5 | Available RAM ÷ the size of one PHP process (check with ps) |
| pm.max_requests | PHP-FPM pool config | 0 (never recycle) | 500-1000, to contain memory leaks |
| fastcgi_read_timeout | nginx config | 60 seconds | ≥ request_terminate_timeout |
After changing PHP-FPM settings, restart it (sudo systemctl restart php8.3-fpm, adjusting the version). If nginx's fastcgi_read_timeout is shorter than PHP's limits, nginx gives up first and visitors get a 504 while PHP is still working.
Fix 6: Check CDN and Proxy Configuration
If your site is behind a CDN like Cloudflare or AWS CloudFront, the CDN has its own timeout settings that can override your server configuration.
| CDN or load balancer | Default | Can you raise it? | Notes |
|---|---|---|---|
| Cloudflare Free, Pro, Business | 125 seconds | No | Shows Error 524, not 504 |
| Cloudflare Enterprise | 125 seconds | Up to 6,000 seconds | Cache Rule or the zone's proxy_read_timeout setting |
| Amazon CloudFront | 30 seconds | 1-120 seconds; more by quota request | Origin settings → Response timeout; GET and HEAD are retried (3 attempts by default) |
| AWS Application Load Balancer | 60 seconds | Yes | The load balancer's idle timeout |
| Google Cloud load balancer | 30 seconds | Yes | Backend service timeout; the classic load balancer shows 502, not 504 |
Cloudflare: on Free, Pro and Business, if your origin hasn't started answering within 125 seconds, Cloudflare gives up and shows Error 524 (Cloudflare). Cloudflare's own advice: speed the request up, move long jobs to the background, or serve them from a DNS-only (grey-cloud) subdomain; Enterprise plans can raise the limit.
CloudFront: raise the origin's response timeout in the distribution's origin settings (AWS). AWS suggests fixing the slow origin first. For GET and HEAD requests CloudFront retries the origin (3 connection attempts by default), so the origin can see the same request several times before the visitor gets the 504.
To see which layer sent the 504, check the response headers in the HTTP Header Checker: server: awselb/2.0 is an AWS load balancer, x-cache: Error from cloudfront is CloudFront, and server: nginx is nginx. Behind Cloudflare every response says server: cloudflare, so there the code itself (524 or 504) is the clue.
Fix 7: WordPress-Specific Solutions
WordPress sites are particularly prone to 504 errors due to heavy plugins, database bloat, and shared hosting limits. Here are targeted fixes.
- Identify slow plugins — Deactivate all plugins, then reactivate one by one. If you cannot access wp-admin, rename the
pluginsfolder via SSH:mv wp-content/plugins wp-content/plugins_disabled. Use the Query Monitor plugin to identify slow database queries. - Install a caching plugin — WP Super Cache, W3 Total Cache, or WP Rocket reduces server-side processing by serving static HTML instead of running PHP on every request.
- Use object caching — Install Redis or Memcached and a WordPress object cache plugin. This caches database query results in memory, reducing MySQL load.
- Clean up the database — Delete old post revisions, transients, spam comments, and orphaned metadata. Use WP-Optimize or WP-Sweep. Add
define('WP_POST_REVISIONS', 5);to limit future revisions. - Move wp-cron to a real cron job — page visits set off WP-Cron, which runs due tasks in a loopback request that takes a PHP worker of its own. Add
define('DISABLE_WP_CRON', true);towp-config.php, then have the server runwp cron event run --due-nowevery 5 minutes.
504 vs 502 vs 503 vs 408: What Is the Difference?
These HTTP error codes are often confused. Here is what each one actually means.
| Code | Name | What Happened | Requires Proxy? |
|---|---|---|---|
| 408 | Request Timeout | Client was too slow sending its request to the server | No — server times out the client |
| 502 | Bad Gateway | Proxy got a broken answer from upstream, or the connection was refused or closed | Yes |
| 503 | Service Unavailable | Server is overloaded or in maintenance and can't handle the request right now | No — any server can return it |
| 504 | Gateway Timeout | Proxy received no response from upstream within the timeout | Yes |
| 524 | A Timeout Occurred | Cloudflare connected to the origin but got no response within 125 seconds | Cloudflare only (non-standard) |
The critical distinction: 502 means the proxy got a broken answer, or the connection was refused or closed; 504 means the proxy's timer ran out while the upstream stayed silent. A 503 doesn't need a proxy: any server can send it when overloaded. A 408 is a client-side timeout (4xx class), where the server gave up waiting for the client.
If you see 502s and 504s together, the backend is probably struggling: requests that time out give 504, and workers that crash or get killed give 502.
If you're seeing the 502 rather than the 504, our 502 Bad Gateway guide walks through the nginx error-log messages that explain it, including a real case from this site.
Does a 504 Error Affect SEO?
Google's documentation describes what 5xx errors do (Google crawler docs):
- Crawling slows down for the whole site, in proportion to the number of URLs returning server errors.
- Indexed pages are kept at first, but URLs that persistently return a server error are eventually removed.
- Crawling recovers gradually once the server answers with 2xx again.
How to Prevent 504 Gateway Timeout Errors
Prevention is better than firefighting. These practices will keep your server responding within timeout limits.
- Set up monitoring — an uptime monitor that loads key pages every few minutes catches 504s before your users report them.
- Match your timeout chain — Ensure CDN timeout ≥ proxy timeout ≥ application timeout. Mismatched values cause unpredictable 504 errors.
- Implement health checks — Load balancers and proxies should health-check upstream servers and route traffic away from unresponsive instances.
- Use caching aggressively — Cache static assets, API responses, and database queries. A cached response is never slow enough to cause a 504.
- Auto-scale — Use horizontal scaling (more instances) so that traffic spikes do not overwhelm a single server.
- Offload heavy work — Move file processing, report generation, email sending, and bulk imports to background job queues. Never do expensive work inside an HTTP request.
- Monitor slow queries — Enable slow query logging in MySQL/PostgreSQL. Set alerts for queries exceeding 1 second.
- Keep dependencies healthy — Monitor third-party APIs your backend depends on. Add timeouts and circuit breakers so one slow API does not cascade into 504 errors for all users.
Check if a server is returning 504
DNS Robot's free HTTP Header Checker requests any URL from our server and shows the status code and headers. server: awselb/2.0 means an AWS load balancer answered, x-cache: Error from cloudfront means CloudFront. Behind Cloudflare every response says server: cloudflare, so there the code (524 or 504) tells you.
Sources
Frequently Asked Questions
What does 504 Gateway Timeout mean?
Is a 504 error my fault?
What does "504 Gateway Time-out: The server didn't respond in time" mean?
What is the difference between a 502 and a 504 error?
What causes a 504 error on nginx?
How do I increase the timeout on nginx?
Can Cloudflare cause a 504 Gateway Timeout?
Does a 504 error hurt SEO?
Why does my WordPress site show a 504 error?
What does a CloudFront 504 error mean?
Related Articles
Related Tools
Website Down Checker
Is it down for everyone or just you? Check any site from 11 places and your own connection, with a live screenshot
HTTP Header Checker
Response headers exactly as sent, with a Mozilla Observatory security grade
Redirect Checker
Follow every redirect hop by hop: 301/302 chains, timing and bulk checks
DNS Lookup
Every DNS record from the domain's own nameservers, beside Google's and Cloudflare's cache



