Explicit timeout values keep cURL from waiting indefinitely on unreachable hosts or slow responses. That matters in shell scripts, CI jobs, health checks, and ad-hoc troubleshooting, where a stalled request is often worse than a fast, clearly handled failure.
The main timeout switches cover different phases of the transfer. Option --connect-timeout limits the connection phase, including name resolution and the TCP plus TLS or QUIC handshake, while --max-time limits how long the full transfer may take. Both options accept decimal seconds, so they can be tuned more precisely than coarse whole-second defaults.
A timeout from cURL returns exit status 28, which makes it practical to branch cleanly in scripts. Set the per-request limits slightly above normal response time, and if you also retry transient failures, keep the overall retry budget separate with --retry-max-time so repeated attempts do not hide a slow or failing dependency. The sample hosts, paths, and file names below stay masked while preserving the shape of a normal API health check and a slower reporting endpoint.
Steps to handle timeouts in cURL:
- Verify the active cURL build exposes the timeout switches you plan to use.
$ curl --help all | grep -E -- '--connect-timeout|--max-time|--retry-max-time' --connect-timeout <seconds> Maximum time allowed to connect -m, --max-time <seconds> Maximum time allowed for transfer --retry-max-time <seconds> Retry only within this periodThe help text can vary slightly by package build, but the option names stay stable across current releases.
- Limit the connection phase so an unreachable host fails quickly instead of waiting for the operating system's longer network timeout.
$ curl --connect-timeout 2 --silent --show-error http://192.0.2.200/ curl: (28) Failed to connect to 192.0.2.200 port 80 after 2001 ms: Timeout was reached
Option --connect-timeout stops the request if DNS lookup plus the TCP and TLS or QUIC handshake cannot finish inside the configured budget.
- Cap the whole request duration with --max-time so a slow response cannot block the terminal or script indefinitely.
$ curl --max-time 2 --silent --show-error https://api.example.net/reports/monthly?profile=slow-response curl: (28) Operation timed out after 2001 milliseconds with 0 bytes received
Set --max-time high enough for normal traffic, because a limit below the service's usual response time will abort healthy requests too.
- Combine connection and total timeouts, then print machine-readable status fields when the command is used inside automation.
$ curl --connect-timeout 2 --max-time 4 --silent --show-error \ --output monthly-report.json \ --write-out "exit_code=%{exitcode}\ntime_total=%{time_total}\n" \ https://api.example.net/reports/monthly?profile=slow-response curl: (28) Operation timed out after 4006 milliseconds with 0 bytes received exit_code=28 time_total=4.006766Send the body to a file such as monthly-report.json or to /dev/null when the script only needs a reliable exit code and elapsed-time metric.
- Verify the same timeout profile still allows a healthy endpoint to finish normally.
$ curl --connect-timeout 2 --max-time 5 --silent --show-error \ --output /dev/null \ --write-out "http_code=%{http_code}\nexit_code=%{exitcode}\ntime_total=%{time_total}\n" \ https://api.example.net/health http_code=200 exit_code=0 time_total=0.301456A successful check keeps exit_code at 0 and returns before the configured --max-time ceiling with enough margin for routine variation.
- Branch on exit status 28 so timeout failures can be retried, logged, or escalated separately from other cURL errors.
$ curl --connect-timeout 2 --max-time 4 --silent --show-error \ https://api.example.net/reports/monthly?profile=slow-response > monthly-report.json curl: (28) Operation timed out after 4006 milliseconds with 0 bytes received $ rc=$? $ [ "$rc" -eq 28 ] && echo "request_status=timeout" request_status=timeout
For idempotent requests, pair this check with --retry and --retry-max-time so transient timeout failures can be replayed without letting the whole retry loop run forever.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
