Timeouts and retries

curl · Practical · 9 min

Without limits, a script can hang forever on a dead server; with retries, it survives brief outages.

By default curl waits a long time: the connect phase times out after 300 seconds and the whole transfer has no time limit. In scripts and health checks, always set limits:

  • --connect-timeout 5 limits the TCP and TLS connect phase.
  • -m 30 / --max-time 30 limits the entire operation. Exceeding either gives exit code 28.

Retrying transient failures:

  • --retry 3 retries up to three times when the error is considered transient: a timeout or an HTTP 408, 429, 500, 502, 503 or 504. Waits double from 1 second each time unless you set --retry-delay.
  • curl honours the server's Retry-After header for 429 and 503 responses.
  • --retry-all-errors retries on any error (including other HTTP errors when used with --fail); use carefully.
  • --retry-max-time 60 caps the total time spent retrying, and --retry-connrefused also retries when the connection is refused (useful while a service is starting).

Be careful with retries on non-idempotent requests: retrying a POST that timed out may create the resource twice if the first attempt actually succeeded. APIs often support an Idempotency-Key header for exactly this.

A good default for scripts: curl -sS --fail-with-body --connect-timeout 5 --max-time 30 --retry 3.

Example

curl -sS --connect-timeout 5 --max-time 20 https://api.example.com/report -o report.json
echo $?        # 28 if it took longer than 20 s

# robust download in CI
curl -fsSL --retry 5 --retry-delay 2 --retry-max-time 60 \
     -o tool.tgz https://releases.example.com/tool.tgz

# wait for a service that is still starting
curl -fsS --retry 10 --retry-connrefused --retry-delay 1 http://localhost:8080/health

# POST with an idempotency key so a retry cannot double-charge
curl -sS --retry 3 -H "Idempotency-Key: $(uuidgen)" --json @order.json https://api.example.com/orders

Remember

  • --connect-timeout for connecting, --max-time for the whole request
  • --retry N handles timeouts and HTTP 408, 429, 500, 502, 503, 504
  • Retrying non-idempotent requests can duplicate work

Watch out for

  • Running curl in cron or CI without --max-time, so a stalled connection blocks the job indefinitely.

Check yourself

  1. Which failures does plain `--retry 3` retry?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: curl.se/docs/manpage.html#--retry