You click "Check for updates" or try to install a plugin, and cpanel" class="auto-link">WordPress stalls. Then it shows something like cURL error 28: Operation timed out after 10001 milliseconds with 0 bytes received. Sometimes it's in Site Health, sometimes in a failed cron event, sometimes in a payment plugin's log. The message looks scary, but it has a short list of causes. Let's walk through them in the order we check them on customer tickets.

What cURL error 28 actually means

WordPress uses PHP's cURL to make outbound requests: update checks against api.wordpress.org, plugin licence checks, webhooks, REST loopbacks, payment gateways. Error 28 simply means the other side didn't answer before the timeout ran out. WordPress's default timeout is short (often 5 to 30 seconds depending on the call), so a slow or blocked connection trips it quickly.

Notice what it doesn't say: it doesn't tell you why nothing came back. That's the job.

Symptoms you'll see

  • Dashboard → Updates hangs, then fails.
  • Site Health shows "The REST API encountered an error" or "Your site could not complete a loopback request" with cURL error 28.
  • Plugin or theme installs time out halfway.
  • WP-Cron events fail and scheduled posts slip.
  • A licence, payment or shipping plugin logs cURL error 28 against its vendor's API.

Cause 1: The remote service is slow or down

Before touching your server, rule out the obvious. If only one plugin's API call fails, the vendor may be having a bad day. Test from the server itself, not your laptop.

curl -sS -o /dev/null -w "dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} total:%{time_total}\n" https://api.wordpress.org/core/version-check/1.7/

Run it over SSH on your cPanel account or VPS. Read the numbers like this:

Slow stageLikely cause
dnsBroken or slow resolver on the server
connectOutbound firewall, routing, or IPv6 issue
tlsMTU problems, old OpenSSL or CA bundle
total (after tls is fast)The remote API is slow

Cause 2: DNS resolution is slow on the server

If dns in the output above is more than a second, that's your culprit. On a VPS, check which resolvers you're using:

cat /etc/resolv.conf
dig api.wordpress.org @1.1.1.1 | grep "Query time"

If a public resolver answers in milliseconds but the system default is slow, change the resolver. On Ubuntu with systemd-resolved, set DNS=1.1.1.1 8.8.8.8 in /etc/systemd/resolved.conf and run systemctl restart systemd-resolved. On shared hosting you can't change this yourself, so raise a ticket with us and mention the timings.

Cause 3: Outbound traffic is blocked by a firewall

Inbound rules get all the attention, but a strict outbound policy will cause exactly this error. On a VPS, check:

  • CSF: look at /etc/csf/csf.conf. TCP_OUT must include 80 and 443. If you've enabled SMTP_BLOCK or LF_ outbound rules, review those too.
  • UFW: run ufw status verbose. If the default outgoing policy is deny, add ufw allow out 443/tcp and ufw allow out 80/tcp, plus 53 for DNS.
  • Cloud firewall: if you've attached egress rules in a control panel, make sure HTTPS is allowed.

A quick test: curl -sS -m 10 -I https://example.com. If that hangs at connect, it's a block, not WordPress.

Cause 4: IPv6 is advertised but doesn't work

This one catches a lot of people. The domain has both A and AAAA records, PHP tries IPv6 first, and your server has no working IPv6 route. The request waits for the full timeout, then maybe falls back. Compare:

curl -4 -sS -m 10 -I https://api.wordpress.org
curl -6 -sS -m 10 -I https://api.wordpress.org

If -4 works instantly and -6 hangs, you've found it. Either fix IPv6 properly or prefer IPv4 by adding this to /etc/gai.conf:

precedence ::ffff:0:0/96  100

Or, as a WordPress-only workaround, force cURL to use IPv4 with a small mu-plugin:

<?php
add_action('http_api_curl', function ($handle) {
    curl_setopt($handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
});

Save it as wp-content/mu-plugins/force-ipv4.php. It only affects WordPress's own requests.

Cause 5: Loopback requests are timing out

When the failing URL is your own domain, WordPress is calling itself (cron, Site Health, REST). That fails when the site resolves to a Cloudflare IP and your origin firewall blocks it, when basic auth or a maintenance plugin sits in front, or when /etc/hosts points the domain somewhere odd. On a VPS, you can sidestep the round trip by pointing the domain to localhost:

echo "127.0.0.1 yourdomain.com www.yourdomain.com" >> /etc/hosts

Only do that if the site is served from that same machine, and remember it's there next time you move servers.

Cause 6: Security plugins or ModSecurity interfering

Some security plugins block outbound calls on purpose. Check whether WP_HTTP_BLOCK_EXTERNAL is set in wp-config.php:

grep -n "WP_HTTP_BLOCK_EXTERNAL\|WP_ACCESSIBLE_HOSTS" wp-config.php

If it's true, only hosts in WP_ACCESSIBLE_HOSTS are allowed. That's by design, but it's easy to forget you set it. If you want updates to work, include *.wordpress.org in the allowed list.

The quick fix: raise the timeout (carefully)

If the remote service is simply slow and you can't change that, give it more time for specific calls rather than globally:

add_filter('http_request_timeout', function ($timeout) {
    return 30;
});

Treat this as a bandage. A longer timeout also means a longer PHP worker tied up per request. If the real problem is DNS or a firewall, you've just made the failure slower.

Prevention

  • Keep outbound 80, 443 and 53 open on any VPS firewall you manage.
  • Use two reliable DNS resolvers on the server, not one.
  • Don't leave AAAA records advertised on a server without working IPv6.
  • Run Site Health after changing firewall rules or moving servers.
  • Replace unreliable plugins whose vendor APIs time out often.

Frequently Asked Questions

Is cURL error 28 a problem with my hosting?

Sometimes, but not usually. It's most often a slow remote API, a DNS lookup delay, or a firewall rule. The curl test from SSH tells you quickly which one, and if the server's own network is at fault, our support team can check it.

Why does it only happen sometimes?

Intermittent timeouts point to a slow resolver, an overloaded remote API, or IPv6 fallback delays. Run the timing command a few times and compare.

Will increasing the timeout fix it?

Only if the remote service is slow but working. If packets are being dropped or blocked, a longer timeout just delays the same failure.

Does cURL error 28 mean my site is hacked?

No. It's a network timeout. But if you see unexpected outbound requests to unfamiliar hosts in your logs, that's a separate thing worth investigating.

Can I fix this on shared cPanel hosting?

You can check wp-config.php, plugins and the IPv4 mu-plugin. Server-level DNS or firewall changes need us, so open a ticket and include your curl timing output.