Explicit timeout values keep cURL from hanging on unreachable hosts or slow responses. That matters in shell scripts, CI jobs, health checks, and ad-hoc troubleshooting, where waiting forever hides the real failure and blocks the next step in the workflow.

Option --connect-timeout limits how long cURL can spend reaching the server, including name resolution plus the TCP and TLS or QUIC handshake. Option --max-time limits the entire transfer, so a response that connects successfully but stalls later still stops at a predictable point.

A timeout returns exit status 28. Use that status to treat timeout failures differently from HTTP errors or certificate problems, and keep any retry budget separate with --retry-max-time so repeated attempts do not hide a slow dependency. The sample hosts and paths below stay masked while preserving the shape of a normal health check and a slower reporting endpoint.

Steps to handle timeouts in cURL:

  1. Limit the connection phase so an unreachable host fails quickly instead of waiting on 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.

  2. Cap the whole request duration so a slow endpoint cannot block the terminal or script indefinitely after the connection succeeds.
    $ curl --max-time 2 --silent --show-error https://api.example.net/reports/monthly?profile=slow-response
    curl: (28) Operation timed out after 2012 milliseconds with 0 bytes received

    Set --max-time above the service's normal response time, or healthy requests will be cut off as timeout failures.

  3. Print machine-readable status fields when a script needs to tell a timeout apart from a successful transfer without parsing the response body.
    $ curl --connect-timeout 2 --max-time 4 --silent --show-error --output /dev/null --write-out "http_code=%{http_code}\nexit_code=%{exitcode}\ntime_total=%{time_total}\n" https://api.example.net/reports/monthly?profile=slow-response
    curl: (28) Operation timed out after 4009 milliseconds with 0 bytes received
    http_code=000
    exit_code=28
    time_total=4.009589

    Discarding the body with --output /dev/null keeps the transcript focused on the status fields that automation usually needs.

  4. Verify the same timeout profile still leaves enough headroom for a healthy endpoint to complete normally.
    $ curl --connect-timeout 2 --max-time 4 --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.184672

    A healthy response should finish with exit code 0 and enough margin below the configured --max-time ceiling for ordinary variation.