Skip to content

/flags/curl/curl-retry

curl --retry: retry transient errors (and what it does not retry)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · curl 8.21.0 (x86_64-w64-mingw32) libcurl/8.21.0 Schannel zlib/1.3.2updated
tool
curl
command
curl
flag
--retry <num>
default
0 (no retries)

curl --retry 3 URL repeats a failed transfer up to three more times, but only for errors curl considers transient: a timeout, an FTP 4xx reply, or HTTP 408, 429, 500, 502, 503, 504, 522 or 524. A 404, a refused connection or a DNS failure is not retried unless you add --retry-all-errors or --retry-connrefused. Between attempts curl waits one second, then doubles the wait (exponential backoff) up to 10 minutes; --retry-delay N replaces the backoff with a fixed delay.

Without and with --retry

The local server answers 503 twice, then 200:

bash
node -e 'const c = {}; require("http").createServer((q, r) => { c[q.url] = (c[q.url] || 0) + 1; if (c[q.url] < 3) { r.statusCode = 503; return r.end("busy\n"); } r.end("ok\n"); }).listen(5344, "127.0.0.1"); setTimeout(() => process.exit(0), 9000)' &
sleep 1
echo "== no retry"
curl --no-progress-meter http://127.0.0.1:5344/a; echo "exit: $?"
echo "== --retry 3"
curl --no-progress-meter --retry 3 --retry-delay 1 http://127.0.0.1:5344/b; echo "exit: $?"
echo "== -sSf, saved to a file"
curl -sSf --retry 3 --retry-delay 1 -o out.txt -w '%{http_code} after %{num_retries} retries\n' http://127.0.0.1:5344/c; echo "exit: $?"; cat out.txt
wait

Output

== no retry
busy
exit: 0
== --retry 3
busy
Warning: Problem : HTTP error. Retrying in 1 second. 3 retries left.
busy
Warning: Problem : HTTP error. Retrying in 1 second. 2 retries left.
ok
exit: 0
== -sSf, saved to a file
curl: (22) The requested URL returned error: 503
curl: (22) The requested URL returned error: 503
200 after 2 retries
exit: 0
ok

Two details are visible here. Without -f, the 503 body of each failed attempt is written to standard output before the retry, so piped output can contain the error pages followed by the real answer; with -o, curl discards the failed data and the file contains only the final body. And -s hides the "Warning: Problem : HTTP error" lines, while -S still shows each curl: (22) error.

What gets retried

Failure--retry+ --retry-connrefused+ --retry-all-errors
Timeout (exit 28)yesyesyes
HTTP 408, 429, 500, 502, 503, 504, 522, 524yesyesyes
Connection refused (exit 7)noyesyes
Could not resolve host (exit 6)nonoyes
HTTP 404 and other 4xxnonoonly with --fail

An HTTP error is a successful transfer for curl unless --fail is set, which is why --retry-all-errors alone does not retry a 404.

OptionEffect
--retry-delay SECONDSFixed wait between attempts instead of backoff; decimals from curl 8.16.0
--retry-max-time SECONDSStop starting new retries once this much time has passed
--retry-connrefusedAlso retry ECONNREFUSED, for example a service still starting
--retry-all-errorsRetry on any error; risky with uploads or piped output
--max-time SECONDSLimit each attempt, so a hung request becomes a retryable timeout
-w %{num_retries}Print how many retries were done (curl 8.9.0 and later)

Waiting for a service in CI

bash
curl -fsS --retry 10 --retry-delay 2 --retry-connrefused --max-time 5 \
  http://127.0.0.1:8080/health

This polls a health endpoint for roughly 20 seconds while the service starts, fails fast per attempt, and exits with the last error code (see curl exit codes) if it never comes up. Errors such as Failed to connect: Connection refused are retried only because of --retry-connrefused.

FAQ

Does curl --retry retry a 404?

No. Only timeouts, FTP 4xx and HTTP 408, 429, 500, 502, 503, 504, 522 and 524 count as transient. To retry every HTTP error, combine --retry with --fail and --retry-all-errors.

Why does curl not retry when the server is down?

A refused connection is not transient by default. Add --retry-connrefused, or --retry-all-errors, which covers every failure.

How long does curl wait between retries?

One second before the first retry, then double each time up to 10 minutes. --retry-delay N sets a fixed delay, and a Retry-After header from the server overrides both. --retry-max-time caps the total.

Sources