Skip to content

/errors/curl/operation-timed-out

curl: (28) Operation timed out after N milliseconds with 0 bytes received

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
exit code
28
versions
curl 7.x, curl 8.x
os
linux, macos, windows

curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received means a time limit set with -m/--max-time (or --connect-timeout, or a libcurl default) expired before the transfer finished. curl exits with code 28 (CURLE_OPERATION_TIMEDOUT). If the message says 0 bytes received and curl -v shows Connected to, the server accepted the connection but never answered; if it fails before Connected to, packets are not getting through, usually because of a firewall.

Reproduce the error

A server on port 4881 that accepts connections and never sends anything, with a 1 second limit. The sed replaces the elapsed milliseconds, which vary slightly between runs:

bash
node -e 'require("net").createServer(() => {}).listen(4881, "127.0.0.1"); setTimeout(() => process.exit(0), 5000)' &
sleep 1
curl -sS -m 1 http://127.0.0.1:4881/ 2>&1 | sed -E 's/after [0-9]+ milliseconds/after N milliseconds/'
echo "exit status: ${PIPESTATUS[0]}"
wait

Output

curl: (28) Operation timed out after N milliseconds with 0 bytes received
exit status: 28

The two timeout options

OptionLimitsTypical message
-m, --max-time SECONDSthe whole operation, connection plus transferOperation timed out after N milliseconds with X bytes received
--connect-timeout SECONDSonly the connection phase (DNS, TCP, TLS)a connection timeout message (wording varies by version), also exit 28

Both accept decimals (-m 2.5). Without either option curl has no overall limit, but the connection phase still stops after curl's built-in connect timeout or the operating system's TCP timeout.

Fix by symptom

  • 0 bytes received, connection succeeded: the server is stuck or slow. Check the application logs, or raise -m if the request is legitimately slow.
  • Some bytes received: the transfer is slower than the limit. Raise -m, or use --speed-limit and --speed-time to abort only when the transfer stalls.
  • Fails during connect: test the port from another machine, check firewalls and security groups, and keep --connect-timeout short in scripts so they fail fast.

Retries in scripts:

bash
curl -fsS --connect-timeout 5 -m 30 --retry 3 --retry-delay 2 https://api.example.com/health

--retry treats a timeout as a transient error and tries again; --retry-all-errors widens that to every error.

Sources