Reference guide · http-status · Published 2026-08-16 · 3 min read

Retry-After header explained

Retry-After header explained: delta-seconds vs date form, how 429 and 503 use it, and how clients retry without hammering the server.

Flat editorial illustration showing a lantern-style status readout with a neat row of stacked directory rails, each rail marked with an abstract tally.
Illustration: this article at a glance.

Retry-After is the HTTP header a server uses to tell a client when it can come back: either a number of seconds, or an absolute HTTP-date. It appears almost always with a throttling or temporary status (429, 503), so it is the part of the contract that turns "wait" from a guess into a promise.

Two valid forms

The header has exactly two legal shapes:

Retry-After: 120
Retry-After: Wed, 21 Oct 2026 07:28:00 GMT

Clients must treat any other value as garbage: a server that sends Retry-After: "2 minutes" or Retry-After: never has to get a sane fallback, and a well-built client falls back to its own exponential backoff instead of crashing.

What uses it

StatusTypical messageWhat the header says
429Too many requestsWait the window before the bucket refills
503Service unavailableWait until the drain is done / the restart lands
301/302 (rare)Redirect replyA delay hint before fetching the new location

How clients should honor it

A correct client does three things:

  1. Parse and clamp. Read the value; if it is a date, compute the delta from now. Never retry instantly, and never sleep for a giant value like 86400 if the job cannot wait; the caller decides.
  2. Retry the same request. Retry with the same method and body, honoring the header before sending the next attempt. A 429 to a POST must not become a GET to the same URL.
  3. Fall back when absent. If the response has no Retry-After, use the status-family default: exponential backoff with jitter (start around 1s, double on each retry, cap at the deadline).
import time

def wait_after(response):
    value = response.headers.get("retry-after")
    if value is None:
        return min(2 ** attempt, 60)  # exponential backoff, capped
    try:
        return float(value)
    except ValueError:
        return 60  # unparseable: fall back to a sane cap

The two sides of the same coin

Verify a stack honors it

Test your throttling path end to end:

for i in 1 2 3 4 5; do
  curl -s -o /dev/null -w "%{http_code} %header{retry-after}\n" https://example.com/api/check
  sleep 1
done

Read the printed status and header pairs, then compare the time between the 429 and the 200 with the Retry-After value. If the client returns at exactly the promised value, the pair works.

When to involve a professional

If third-party clients consistently report "locked out" on a 429/503 while your own tests pass, the client is ignoring the header or your proxy is stripping it. Ask the vendor or check the edge: many CDNs drop response headers, and a Retry-After that never reaches the client can be restored at the edge layer.

Need a website built, fixed, optimised, migrated or replaced?

This technical resource is written by CSMBAC, a small design and development studio. If you would rather hand the problem to a professional, the website service page explains how we build enquiry-ready websites.

Explore website services