HTTP 503 Service Unavailable
503 is the "come back later" code. The key word is temporarily: the server expects to recover. RFC 9110 says it may send Retry-After to suggest how long to wait.
503 Service Unavailable
The server is temporarily unable to handle the request, due to overload or scheduled maintenance.
Who fixes it: Server. Clients should retry later, ideally after Retry-After. The server side has to restore capacity or finish maintenance.
What 503 means
It's the right code for planned maintenance, for shedding load when a server is saturated, and for "no healthy backend" situations at a load balancer.
Unlike 500, a 503 tells clients and crawlers that the URL is fine and retrying later is reasonable.
Source: RFC 9110 §15.6.4.
Common causes
- Planned maintenance mode during deploys or database migrations.
- Overload: the app or a dependency is saturated and starts rejecting work (full connection pool, exhausted worker pool, queue backpressure).
- Kubernetes: no ready pods behind the Service. Readiness probes are failing, the Service selector doesn't match the pod labels, or every pod is restarting. ingress-nginx then answers
503 Service Temporarily Unavailable. - AWS ALB: the target group has no registered targets.
- nginx
limit_reqandlimit_connreject excess requests with 503 by default. For rate limits, setlimit_req_status 429. - An upstream dependency is down and your app reports it as 503, which is correct, rather than 500.
How to debug and use 503
Kubernetes: does the Service have endpoints?
An empty endpoints list means no pod is ready or the selector matches nothing.
kubectl get endpointslices -l kubernetes.io/service-name=my-service
# Why aren't pods ready?
kubectl get pods -l app=my-app
kubectl describe pod <pod-name> # look for "Readiness probe failed"
# Does the selector match the pod labels?
kubectl get service my-service -o jsonpath='{.spec.selector}'nginx: a maintenance switch with Retry-After
Create the flag file to enable maintenance and delete it to disable. always makes nginx add the header to the 503 response.
server {
error_page 503 /maintenance.html;
location = /maintenance.html {
root /var/www/static;
add_header Retry-After 3600 always;
internal;
}
location / {
# touch /var/www/maintenance.on to enable
if (-f /var/www/maintenance.on) {
return 503;
}
proxy_pass http://127.0.0.1:3000;
}
}Node.js: fail readiness during shutdown
On SIGTERM, report not-ready with 503 so the load balancer stops sending traffic, finish in-flight requests, then exit. This removes the 502/503 blips during rolling deploys.
let shuttingDown = false;
process.on('SIGTERM', () => {
shuttingDown = true;
server.close(() => process.exit(0));
});
app.get('/healthz/ready', (req, res) => {
if (shuttingDown || !db.isConnected()) {
return res.status(503).set('Retry-After', '5').send('not ready');
}
res.send('ok');
});Headers that matter with 503
- Retry-After
- Seconds (
Retry-After: 3600) or an HTTP date. Respected by well-behaved clients and by Googlebot. - Cache-Control: no-store
- Keeps a CDN from caching the maintenance page in place of real content.
503 vs similar status codes
- 500 Internal Server Error: An unexpected failure. 503 is an expected, temporary condition.
- 502 Bad Gateway: The proxy reached an upstream that responded badly. Some proxies send 503 when no upstream is available at all.
- 429 Too Many Requests: Aimed at one client that's sending too much, not the whole service.
SEO impact of 503
Google recommends 503 for planned downtime: Googlebot treats the outage as temporary and comes back later instead of indexing your maintenance page. Keep it short, because if a site returns 503 for more than a couple of days Google may start dropping URLs. A 5xx response for robots.txt makes Google pause crawling the whole site.
Related status codes
502Bad Gateway
A gateway or proxy received an invalid response from the upstream server it contacted.
504Gateway Timeout
A gateway or proxy didn't receive a timely response from the upstream server.
429Too Many Requests
The client has sent too many requests in a given amount of time.
500Internal Server Error
The server encountered an unexpected condition that prevented it from fulfilling the request.
Looking for another code? Search the full HTTP status codes list, or read which code your API should return in the REST API status codes guide.
Learn more
HTTP Status Codes for REST APIs: 200 vs 201 vs 204, 400 vs 422 vs 429
A practical guide to choosing the right HTTP status code in REST API design. Covers the most confusing pairs: 200 vs 201, 400 vs 422, 401 vs 403, and when to use 503 vs 429.
REST API Design Best Practices: A Practical Guide
The conventions that make REST APIs intuitive and consistent. Covers URL design, HTTP methods, status codes, versioning, pagination, and error responses.
CORS Explained: Why It Happens and How to Fix It
CORS errors happen when a browser blocks a request to a different origin. Learn how the Same-Origin Policy works, what preflight requests are, and how to configure CORS correctly in Express, FastAPI, and Nginx.
Frequently Asked Questions
How long does a 503 Service Unavailable last?▾
There's no fixed duration; it lasts until the server recovers or maintenance ends. If the response includes Retry-After, that's the server's own estimate. For visitors, waiting a few minutes and reloading is usually enough.
Should I return 503 during maintenance?▾
Yes. 503 with a Retry-After header tells browsers, API clients and search engines that the outage is temporary. A 200 maintenance page risks being cached or indexed, and 404 or 500 describe the wrong problem.
What is the difference between 503 and 429?▾
429 is aimed at one client: you, specifically, are sending too many requests. 503 is about the server as a whole: it's overloaded or down for everyone. Both can carry Retry-After.