Skip to content
RU

curl: (28) Operation Timed Out. Find the Phase That Stalled and Fix It

What it means: curl gave up because a time limit expired before the request finished.

  1. Read which phase the message names
  2. Time each phase with curl -w
  3. Check the port is open from outside
  4. Fix the slow resolver, firewall or backend
  5. Then set timeouts deliberately

Test your URL now

Pings your host from our server, so you see whether it answers from outside your network.

Check your host & ports →

What curl error 28 means

Exit code 28 is libcurl's CURLE_OPERATION_TIMEDOUT, documented as «Operation timeout. The specified time-out period was reached according to the conditions» (libcurl error codes). curl did not get an error from the network; a timer ran out. Which timer, and in which phase, is in the message after the code. In the curl source (lib/multi.c) the texts are:

  • Resolving timed out after N milliseconds — the DNS lookup never finished.
  • Connection timed out after N milliseconds — the name resolved, but the TCP (and TLS) handshake did not complete in time.
  • Operation timed out after N milliseconds with X out of Y bytes received (or with X bytes received when the size is unknown) — connected, but the whole transfer exceeded --max-time.
  • Operation too slow. Less than N bytes/sec transferred the last M seconds — the low-speed guard (--speed-limit/--speed-time) fired.

Recent curl versions also report a connect-phase timeout as Failed to connect to example.com ... after 10002 ms: Timeout was reached; the exit code is still 28. It is not exit 7 (CURLE_COULDNT_CONNECT: the host answered and refused), and not exit 6 (the name does not exist). A timeout means silence: nothing answered at all within the limit.

Causes by message

MessageWhat stalledUsual causeWhere to look
Resolving timed outDNS lookupResolver in /etc/resolv.conf unreachable or dropping UDP/53dig example.com, resolver config
Connection timed out / Timeout was reachedTCP or TLS handshakeFirewall or cloud security group drops SYN, wrong IP in DNS, host down, outbound port blockednc -vz, tcpdump on the server
Operation timed out after N ms with X bytesThe responseSlow backend, long query, large file with a short --max-timeServer and application logs
Operation too slowThroughputCongested link, throttling, stalled upload--speed-limit settings, the path

The defaults matter. libcurl's connect timeout defaults to 300 seconds (CURLOPT_CONNECTTIMEOUT) and the overall timeout (CURLOPT_TIMEOUT) to 0, meaning never. So when you see error 28 after a few seconds, some code set a limit: your script, a wrapper library, a CI job or a .curlrc. A limit of 2 seconds on an endpoint that needs 3 is a configuration problem, not a network one.

A connect timeout where the TLS handshake is the slow part is still reported as a connection timeout: the curl manual says the connection phase is complete only «when the DNS lookup and requested TCP, TLS or QUIC handshakes are done».

In PHP, Git and other libcurl users

Everything built on libcurl reports the same code. PHP returns 28 from curl_errno() with the same text from curl_error(); the limits are CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT (or their _MS variants). Git prints it inside its own error, for example error: RPC failed; curl 28 Operation too slow.... Git's low-speed guard is configurable: http.lowSpeedLimit and http.lowSpeedTime, or the GIT_HTTP_LOW_SPEED_LIMIT and GIT_HTTP_LOW_SPEED_TIME environment variables (git-config).

Behind a proxy, the timeout may be on the way to the proxy rather than to the site. Run env | grep -i _proxy first: a stale https_proxy pointing at a host that no longer exists produces exactly this error for every URL.

How to fix it

  1. Time each phase. The -w variables show where the seconds go:
    curl -sS -o /dev/null --max-time 60 \
      -w 'dns:%{time_namelookup} tcp:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n' \
      https://example.com/
    A large dns value points at the resolver, a large gap between dns and tcp at the network path, and a large gap between tls and ttfb at the application.
  2. DNS phase: compare your resolver with a public one: dig example.com and dig example.com @1.1.1.1. If only the first hangs, fix /etc/resolv.conf or the resolver it names.
  3. Connect phase: test the port without HTTP: nc -vz -w 5 example.com 443. On the server, watch whether the SYN arrives at all:
    tcpdump -ni any 'tcp port 443 and tcp[tcpflags] & tcp-syn != 0'
    No packets means a firewall, security group or routing problem before the server. Packets but no reply means the host firewall drops them or nothing listens (ss -ltn 'sport = :443').
  4. Transfer phase: the server accepted the request and was slow. Check the application and proxy logs for the request time, slow database queries and upstream timeouts. Fixing the slow endpoint beats raising the limit.
  5. Then set the limits on purpose, short for connecting and generous for the transfer, with retries for transient failures:
    curl --connect-timeout 10 --max-time 300 --retry 3 https://example.com/file.tar.gz
    The curl manual counts a timeout as a transient error, so --retry covers it.

How to confirm the fix

curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' --connect-timeout 10 https://example.com/
# 200 0.412s
echo $?
# 0

Run it from the machine that failed, not only from your laptop: a timeout is a property of the path. To see whether the host and port answer from a network outside yours, use the ping and port checker.

Related errors

ICMP PingHost availability and latency
Port ScannerOpen TCP port detection
LatencyResponse time in milliseconds
Packet LossPercentage of dropped packets

Why teams trust us

ICMP+TCP
check protocols
14
key ports scanned
3,184
checks in 30 days
3
regions

How it works

1

Enter IP or domain

2

ICMP packets sent

3

Latency & packet loss shown

How Do Ping and Port Scanning Work?

Ping sends ICMP packets to a host and measures response time. Port scanning checks which TCP ports are open and accepting connections — helping diagnose serviceavailability issues.

Configurable Ping

Choose packet count (3, 4, 6, 10). Stats: min/avg/max latency and packet loss.

Common Port Scanner

Check 14 key ports: HTTP, HTTPS, SSH, FTP, SMTP, MySQL, PostgreSQL, and more.

Cloud-Based Check

Testing from our server — see site availability from outside, not just your local network.

Uptime Monitoring

Need constant monitoring? Create a monitor — checks every minute with notifications.

Who uses this

DevOps

availability diagnosis

Network engineers

TCP port scanning

Developers

connection debugging

SRE

basic health check

Common Mistakes

ICMP blocked = server is downMany servers block ICMP. Ping fails but site works — check ports instead.
High ping = server problemLatency depends on geography. 150ms between continents is normal, not an error.
Closed ports — cause for alarmClosed ports of unused services are good. Unnecessary open ports are a risk.
One check = sufficientNetworks are unstable. A single timeout ≠ a problem. Check multiple times or set up monitoring.

Best Practices

Combine ping and port checksPing shows host availability, ports show specific service availability. Use both.
Check from different locationsThe problem may be local. A cloud test shows the real picture.
Close unused portsEvery open port is a potential attack vector. Keep only necessary ports open.
Set up monitoringManual checks do not scale. Set up automated monitoring with notifications.

Get more with a free account

Ping check history, host availability monitoring and downtime alerts.

Sign up free

Learn more

Sources

Frequently Asked Questions

What is the difference between curl error 28 and error 7?

Error 7 means the connection attempt got an answer and failed, usually a refused port. Error 28 means nothing answered before the time limit ran out, which points at a firewall dropping packets, a wrong address or a stalled server.

Does curl have a timeout by default?

libcurl waits up to 300 seconds to connect and has no overall limit by default. If you get error 28 after a few seconds, a timeout was set explicitly by your command, script, library or .curlrc.

What does --connect-timeout cover?

The connection phase only: the DNS lookup and the TCP, TLS or QUIC handshake. The transfer after that is limited by --max-time.

Why does Git fail with RPC failed; curl 28?

Git uses libcurl, and its low-speed guard aborts transfers slower than http.lowSpeedLimit for http.lowSpeedTime seconds. Fix the slow link or proxy, or adjust those two settings for a very large repository.

Should I just raise the timeout?

Only after you know which phase is slow. A connect timeout is rarely fixed by waiting longer, because a dropped SYN never gets an answer; a slow download may legitimately need a larger --max-time.

Try the live tool that powered this guide

Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.