A 503 Service Unavailable error means the web server received the request but cannot handle it right now. The server is reachable, so DNS and the network work, but the application behind it is overloaded, in maintenance or unable to reach a service it depends on. A 503 is meant to be temporary. If it lasts more than a few minutes, something needs fixing: usually too much traffic, too few workers, a stopped application process or a backend that is down.
This guide explains what triggers a 503, how to find the cause on your own server, how to fix each one and how to make sure you hear about the next one before your customers do.
What a 503 actually tells you
HTTP status codes in the 5xx range mean the server failed, not the visitor. Within that family, 503 has a specific meaning: the service is unavailable for now and the client may try again later. Compare it with its neighbours:
- 500 Internal Server Error: the application crashed while handling the request.
- 502 Bad Gateway: a proxy or load balancer got an invalid answer from the server behind it.
- 503 Service Unavailable: the server, or something in front of it, refuses to process the request because it is overloaded, in maintenance or has nothing healthy to send it to.
- 504 Gateway Timeout: a proxy waited for the server behind it and gave up.
The distinction matters because it points to where to look. A 503 is rarely a bug in one page. It is almost always about capacity or availability of a whole service. For a full overview of the codes and which ones a monitor should treat as down, see our HTTP status codes cheat sheet for monitoring.
Common causes of a 503
Traffic spikes and overload
Every server can handle a limited number of requests at the same time. A campaign email, a mention on social media or a bot crawling thousands of pages can push it past that limit. When the queue is full, the web server or the application starts rejecting new requests with 503. The site often works again a few minutes later, and then fails again at the next peak.
Planned maintenance
Many systems return 503 on purpose during maintenance. WordPress does it while it installs updates: it writes a .maintenance file and serves a short “Briefly unavailable for scheduled maintenance” page with status 503. If an update is interrupted, that file can stay behind and the site keeps returning 503 until someone deletes it.
Stopped application process or app pool
On Windows servers running IIS, a stopped or crashed application pool produces the classic “HTTP Error 503. The service is unavailable.” The pool can stop because of repeated crashes, a wrong identity password or a configuration change. On Linux, the equivalent is a Node, Python or Java process that has exited, leaving the reverse proxy with nothing to forward to.
PHP-FPM out of workers
PHP sites behind nginx or Apache usually run PHP-FPM with a fixed number of worker processes, set by pm.max_children. When every worker is busy, for example because each request waits on a slow database query or an external API, new requests queue up. Depending on the setup the visitor gets a 503, a 502 or a 504. The PHP-FPM log tells you if this is happening:
WARNING: [pool www] server reached pm.max_children setting (10), consider raising it
Rate limiting
Rate limits protect a server from abuse, but they return errors to real users too if they are set too tight. nginx returns 503 by default when a request exceeds a limit_req zone. Web application firewalls and some hosting platforms do the same. If one office, one API client or one monitoring service shares an IP address with many users, they can hit the limit together.
Upstream or backend down
Load balancers and reverse proxies return 503 when they have no healthy server to send traffic to. If health checks mark every backend as unhealthy, after a bad deploy or because the database is down and the health endpoint reports it, the proxy answers 503 for every request.
CDN and origin problems
If your site sits behind a CDN, the 503 may come from the CDN rather than your server. The CDN can return it when your origin is overloaded or unreachable, or when the CDN itself has trouble in one region. The response headers usually tell you who answered: look for the CDN’s own server header or request ID, and compare with a request sent straight to the origin.
How to find the cause
Start with the response itself. Request the failing URL and look at the headers:
curl -sS -o /dev/null -D - https://northwind.shop/checkout
The Server header and any CDN-specific headers show which layer answered. A Retry-After header suggests deliberate maintenance. Then work inward:
- Check whether it is everywhere. Does the homepage fail too, or only one path? A single path points to one application route or worker pool; everything failing points to the server or proxy.
- Read the web server error log. nginx and Apache log upstream failures, rate limit rejections and connection errors with timestamps.
- Read the application or PHP-FPM log. Look for
max_childrenwarnings, crashes, out-of-memory kills and slow request traces. - Check server resources. CPU, load, memory and swap at the moment of the error. A server that swaps is a server that answers slowly, and slow answers fill worker pools.
- Check dependencies. Is the database answering? Is the cache running? Does an external API you call synchronously respond slowly?
- Check recent changes. A deploy, a plugin update, a configuration change or a new rate limit around the time the errors started is the likeliest cause.
How to fix a 503
The fix follows the cause. Here are the common ones in the order most teams meet them.
- Stuck maintenance mode: remove the
.maintenancefile in the WordPress root, or switch off your framework’s maintenance flag, then finish or retry the update. - Overload from real traffic: cache what you can at the edge and in the application, so most requests never reach PHP or the database. Then add capacity: more workers if memory allows, a bigger server or more servers behind the load balancer.
- Overload from bots: identify the user agents and IP ranges in your access log and rate limit or block them at the CDN or firewall, before they reach the application.
- PHP-FPM workers: raise
pm.max_childrenonly as far as memory allows. Work out the average memory of one worker and divide the memory you can spare by it. If workers are busy because of slow queries, fix the queries first, or you only move the bottleneck. - Stopped app pool or process: restart it, then find out why it stopped. Check the event log or system journal for crashes, and set up a process manager that restarts the service automatically.
- Rate limits too strict: raise the limit or the burst size, exempt known IP addresses such as your office or your monitoring service, and return 429 instead of 503 for rate-limited clients so the cause is obvious in logs.
- Unhealthy backends: check what the load balancer health check requests and why it fails. Roll back a bad deploy first and investigate after.
Here is a typical PHP-FPM pool change for a server with room for more workers. The numbers are an example, not a recommendation for your server:
; /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 24
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 10
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/www-slow.log
The slow log is the useful part: it shows which scripts hold workers the longest, which is where to look next.
Use Retry-After during planned maintenance
When you take a site down on purpose, return 503 with a Retry-After header. It tells browsers, API clients and search engine crawlers that the outage is temporary and when to come back. The value is either a number of seconds or an HTTP date:
HTTP/1.1 503 Service Unavailable
Retry-After: 1800
Content-Type: text/html; charset=utf-8
In nginx, a simple maintenance switch can look like this:
if (-f /var/www/maintenance.flag) {
return 503;
}
error_page 503 @maintenance;
location @maintenance {
add_header Retry-After 1800 always;
root /var/www/maintenance;
rewrite ^ /index.html break;
}
Two rules make planned maintenance painless. Return 503, never 200 with a “back soon” page, because a 200 tells crawlers and monitors that the maintenance page is your real content. And keep it short: a 503 for an hour is fine, a 503 for days risks pages dropping out of search results.
Tell customers in advance too. A note on your status page answers “is it just me?” before anyone asks.
How monitoring catches 503s
A 503 often comes and goes. The site fails for two minutes at the peak of a campaign, recovers, and fails again an hour later. Nobody on the team sees it, because by the time someone opens the site it works. Customers saw it, though.
An HTTP monitor requests your pages on a schedule and records the status code and response time of every check. A 503 is a failed check. Good monitoring then does three things:
- Confirms the failure. A second check, ideally from another location, rules out a problem on one network path. Uptimecheck checks from Europe and checks a failed request again a few seconds later before it opens an incident.
- Alerts the right people. The alert contains the status code, the URL and when it started, so whoever picks it up knows it is a 503 and not a DNS error. See alerts and notifications for the channels.
- Records the pattern. Incident history shows whether 503s cluster around traffic peaks, deploys or nightly jobs, which tells you which fix to try first.
Monitor more than the homepage. The homepage is often cached and keeps working while checkout, login or the API fail. Add uptime monitors for the pages that earn money, and watch the response time trend: a page that slows down every day at the same hour is often a 503 waiting to happen. Our guide on what a good website response time is explains what to look for.
Server metrics close the loop. When a 503 alert arrives, the first question is whether the server ran out of CPU, memory or disk. With server monitoring next to your uptime checks, you see the cause and the symptom side by side.
503 checklist
- Look at the response headers to see which layer returned the 503.
- Check the web server, application and PHP-FPM logs for the same timestamp.
- Check CPU, memory, swap and disk on the server.
- Look for deploys, updates and configuration changes just before the errors started.
- Fix the cause: caching, more workers, a restarted process, a looser rate limit or a healthy backend.
- Use 503 with
Retry-Afterfor planned maintenance, never 200. - Monitor key pages every minute and confirm failures from a second location.
Summary
A 503 means the server is there but cannot serve you right now. It is a capacity or availability problem, not a broken page, and the logs at the same timestamp usually point straight at the cause. Fix the cause rather than the symptom, use Retry-After when the downtime is planned, and let monitoring tell you about short 503s you would otherwise never see.
Uptimecheck monitors websites, APIs and servers in one account and alerts you when a page starts returning 503. Start your 14-day free trial, no credit card required.