DEVESSENTIALS

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.

5xx · Server errorRFC 9110 §15.6.4

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_req and limit_conn reject excess requests with 503 by default. For rate limits, set limit_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

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

Browse all developer guides →

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.