ERROR · 28 · VERIFIED 2026-10allwpcare.com/errors/download-failed-curl-error/
Errors / download-failed-curl-error

Download failed. cURL error 6: Could not resolve host

The words after Download failed. name the step that stopped: DNS, a blocked host, a bad address or a 404. Test the lookup from the server, then fix that step.

The message you see
1−Download failed. cURL error 6: Could not resolve host: mysite.invalid
Last verified Oct 2026Tested with WordPress 7.1Applies to WordPress 7.1 (tested) · PHP 7.4+

Why it happens

  • The server could not turn the host name into an address (DNS). The message reads "cURL error 6: Could not resolve host: ...". WordPress checks a name before it downloads, so you only see this when that check was skipped (the package is on your site's own address and the server cannot resolve that domain) or when the lookup worked for the check and failed a moment later.
  • The name did not resolve at all, or the address is not allowed. The message is only "A valid URL was not provided." A host that DNS cannot find, a host that points to a private or loopback address, a port other than 80, 443 or 8080, a user name and password in the address, and a missing https:// all give this.
  • WP_HTTP_BLOCK_EXTERNAL is set to true in wp-config.php. The message is "User has blocked requests through HTTP to the URL: ...".
  • The server was reached and answered with an error. The message is the HTTP status text: "Not Found", "Forbidden", "Unauthorized", "Service Unavailable". The package address is wrong, expired or needs a licence.
  • The connection itself failed: cURL error 7 (nothing listening or a firewall refusal), 28 (timed out) or 35 (the secure handshake failed).

How to fix it

Try the fixes in this order. Each one is independent: stop as soon as the error is gone.

FIX 01

Read what follows "Download failed."

  1. "Download failed." is only the start. WordPress prints the real reason after it. Match it with the table in this page: "cURL error 6" is a name lookup, "A valid URL was not provided." is the address check, "User has blocked requests" is the block setting, a plain word such as "Not Found" is an HTTP status.
  2. With WP-CLI the reason is printed in quotes: Warning: Download failed. "Not Found". In the dashboard it follows the words on the same line.
FIX 02

Test the name lookup from the server, not from your laptop

  1. Your browser can reach downloads.wordpress.org when your server cannot. Over SSH run getent hosts downloads.wordpress.org and curl -sS -o /dev/null -w "http=%{http_code} dns=%{time_namelookup}s\n" https://downloads.wordpress.org/plugin/akismet.zip. On a healthy server the first prints an address and the second prints http=200.
  2. If curl ends with curl: (6) Could not resolve host, the server's DNS is the problem, and no WordPress setting changes that. Check /etc/resolv.conf, then ask your host to fix the resolver or open outgoing DNS (port 53). Give them the command and its output.
  3. If the lookup works when you test but the error comes and goes, run the update again. WordPress looks the name up twice, once for its own check and once in cURL, so a resolver that answers one and not the other gives this message. Ask your host about their DNS, and give them the output of both commands.
FIX 03

Fix a package that lives on your own domain

  1. WordPress skips its own name check for a package on the same host as your Site Address (URL) in Settings → General. Then cURL does the only lookup, and if your server cannot resolve its own domain you get cURL error 6. It happens with a premium plugin that updates from your own site, behind some proxies, and on staging copies.
  2. Check with getent hosts yourdomain.com on the server. If it prints nothing, the server cannot find its own domain. Fix the DNS record or the server's resolver, or ask your host to. Give them the output of the command.
  3. If you moved the site and only the WordPress Address (URL) or only the Site Address (URL) is the new domain, set both to the same address. WordPress uses the Site Address for the name check and the WordPress Address for the block setting (next fix), so a mismatch gives odd results.
FIX 04

Turn off the block, or allow the hosts WordPress needs

  1. Open wp-config.php and look for define( 'WP_HTTP_BLOCK_EXTERNAL', true );. Your host, a security plugin or a former developer may have added it. Remove the line, or set it to false, and run the update again.
  2. If the block must stay, allow the hosts WordPress talks to: define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,*.wordpress.org' );. *.wordpress.org covers downloads.wordpress.org. With the block on and that list, a plugin update downloaded and installed. With a list that held only api.wordpress.org the download stayed blocked.
  3. Requests to localhost and to your own site (the WordPress Address) are never blocked by this setting, so a package on your own domain still works.
FIX 05

Fix an address that the check rejects

  1. "A valid URL was not provided." with an address that looks fine means wp_http_validate_url() said no. Test the host: getent hosts the-host-name. No answer means DNS (second fix). An answer starting with 127., 10., 192.168. or 172.16 to 172.31 means the name points to a private address. A common cause is a hosts-file line that blocks the update server.
  2. Remove that line, or if the private address is intended, let it through with a small mu-plugin: add_filter( 'http_request_host_is_external', function ( $external, $host ) { return 'updates.example.com' === $host ? true : $external; }, 10, 2 );.
  3. For a port other than 80, 443 or 8080, allow it: add_filter( 'http_allowed_safe_ports', function ( $ports ) { $ports[] = 9999; return $ports; } );. This applies to an outside host. A port is also accepted when the address uses the same host and port as your Site Address.
  4. Take a user name and password out of the address and make sure it begins with http:// or https://. Both are rejected, and so is a redirect to a host that does not resolve.
FIX 06

Fix a Not Found, Forbidden or Unauthorized download

  1. These come from the server that holds the zip, so the connection is fine. Open the address from the "Downloading update from" line on the same screen. From the server run curl -sSI "ADDRESS" to see the status.
  2. Not Found (404) means the file is gone or the address is mistyped. Update the plugin's licence or its update source, or install the latest zip by hand. Forbidden (403) and Unauthorized (401) usually mean an expired licence or a firewall that blocks your server's address. Service Unavailable (503) is temporary. Wait and retry.
FIX 07

Install the zip by hand when the server cannot download

  1. Download the plugin zip on your computer, then use Plugins → Add New Plugin → Upload Plugin. The upload does not use the download step, so none of these checks run.
  2. With WP_HTTP_BLOCK_EXTERNAL on, installing a local zip worked, and installing by name failed with "An unexpected error occurred", because the call to the plugin directory was blocked before any download started.
  3. This is a workaround. Fix the cause too, or the next update will fail the same way.

"Download failed. cURL error 6: Could not resolve host" means your server could not turn the host name of the zip into an address. Run getent hosts the-host-name and curl -I https://the-host-name/ over SSH. If they fail too, the server's DNS is the problem; if the host is your own domain, see the third fix.

"Download failed." is only a heading. The words after it name the step that stopped: a name lookup, an address check, the block setting, the connection or the server's answer. Each has a different fix, and the table below sorts them. Nothing on your site was changed: the old version is still in place.

What you see#

The message appears on the Update Plugin screen after you click Update now, in the update log, and in WP-CLI. This is the lookup variant on WordPress 7.1.4, with a package on the site's own address that the server cannot resolve:

The Update Plugin screen. Downloading update from http://race.example.test/akismet.zip. Then: Download failed. cURL error 6: Could not resolve host: race.example.test. A link says Go to Plugins page.
WordPress 7.1.4. A test update for Akismet whose zip sits on mysite.invalid, which is also the site's Site Address, a name this server cannot resolve.

The same text in WP-CLI is quoted:

Output
Downloading update from http://mysite.invalid/akismet.zip...Warning: Download failed. "cURL error 6: Could not resolve host: mysite.invalid"Error: No plugins updated (1 failed).

How the download works#

WP_Upgrader::download_package() calls download_url(), which uses wp_safe_remote_get(). If that returns an error, the upgrader wraps it: the error message becomes the string "Download failed." and the original reason is attached as data. The upgrade screens print the two together. So you see one fixed prefix and a reason that differs by case.

The "safe" request runs more checks than a normal one, in this order:

Five stacked stages of one download. 1 the URL check, which gives A valid URL was not provided. 2 the block setting, which gives User has blocked requests through HTTP. 3 the name lookup, which gives cURL error 6. 4 the connection, which gives cURL error 7, 28 or 35. 5 the answer, which gives an HTTP status such as Not Found. If all five pass the zip arrives.
The first stage that fails decides the words after Download failed.

Stage 1 asks PHP for the host's address (gethostbyname(), see the PHP manual). That is why an unknown host never reaches cURL during a download: the check says no first. Stage 3 asks again, through cURL. So cURL error 6 on a download means one of two things: stage 1 was skipped (the package is on your own Site Address, see the third fix) or the lookup passed stage 1 and then failed in cURL. I reproduced the first. For the second I removed a hosts-file entry between the two lookups to stage it; I did not test other resolver differences, such as IPv6 answers.

Which message means what#

All results on this page come from a disposable lab site running WordPress 7.1.4, PHP 8.3 and cURL 8.14.1.

After "Download failed."StageTypical causeReproduced by
A valid URL was not provided.1Name does not resolve, resolves to a private address, port not 80, 443 or 8080, user:pass in the address, no http(s)://, redirect to an unresolvable hostEach case in turn
User has blocked requests through HTTP to the URL: ...2WP_HTTP_BLOCK_EXTERNAL is true and the host is not in WP_ACCESSIBLE_HOSTSSetting the constant
cURL error 6: Could not resolve host: ...3The package is on your own Site Address and that domain does not resolve, or DNS failed after the check passedOwn-domain case; host removed after the check (staged)
cURL error 7: Failed to connect to ...4Nothing listening on that portPort with no server
cURL error 35: TLS connect error4https address on a port that speaks plain httphttps to a plain port
Not Found, Forbidden, Unauthorized, Gone, Internal Server Error, Service Unavailable5The server answered with that statusA test server returning each code

cURL error 28 (timed out) also lives at stage 4. It has its own page: cURL error 28: operation timed out. I did not reproduce cURL error 60 (certificate problems), so it is not in the table.

The same screen, three more times#

The block setting:

The Update Plugin screen. Download failed. User has blocked requests through HTTP to the URL: https://downloads.wordpress.org/plugin/akismet.5.3.zip.
With define( 'WP_HTTP_BLOCK_EXTERNAL', true ); in wp-config.php. The message names the whole address.

A file that does not exist on the real download server:

The Update Plugin screen. Downloading update from https://downloads.wordpress.org/plugin/akismet.0.0.0-no-such-version.zip. Download failed. Not Found.
downloads.wordpress.org answered 404 for a version that does not exist. The reason is the status text, with no number.

A host name that DNS cannot find. This is the one people expect to read "could not resolve host" and do not:

The Update Plugin screen. Downloading update from https://nonexistent-host.invalid/akismet.zip. Download failed. A valid URL was not provided.
Stage 1 catches the unknown host, so the message never mentions DNS.

Test it on the server#

Run these over SSH. A healthy server gives:

Terminal
getent hosts downloads.wordpress.orgcurl -sS -o /dev/null -w "http=%{http_code} dns=%{time_namelookup}s\n" https://downloads.wordpress.org/plugin/akismet.zip
Output
2620:109:b00a::4206:2afa downloads.wordpress.orghttp=200 dns=0.002522s

A name that does not exist gives cURL's own version of the error:

Terminal
curl -sS -o /dev/null https://nonexistent-host.invalid/
Output
curl: (6) Could not resolve host: nonexistent-host.invalid

To ask WordPress itself whether it accepts an address, run wp eval 'var_dump( wp_http_validate_url( "https://example.com/a.zip" ) );'. Results for these addresses:

AddressResult
https://downloads.wordpress.org/plugin/akismet.zipaccepted
https://nonexistent-host.invalid/a.ziprejected (no such host)
a name mapped to 127.0.0.1 in /etc/hostsrejected (loopback)
https://downloads.wordpress.org:8443/a.ziprejected (port)
https://user:pw@downloads.wordpress.org/a.ziprejected (credentials)
downloads.wordpress.org/a.ziprejected (no scheme)
ftp://downloads.wordpress.org/a.ziprejected
https://[::1]/a.ziprejected
http://localhost:8902/a.zip on a site whose Site Address is http://localhost:8902accepted (same host and port as the site)
http://localhost:8903/a.zip on the same siterejected (other port)

Why a name that works in your browser fails here#

The browser uses your computer's DNS. PHP uses the server's resolver, set in /etc/resolv.conf or by the host. A DNS outage, a blocked outgoing port 53 or a bad resolver on the server breaks WordPress and leaves your browser fine. That is why the test above must run on the server.

The own-domain case is the one guides miss. WordPress trusts a package on the same host as your Site Address (URL) (the home option) and skips stage 1. The block setting looks at a different option, the WordPress Address (URL) (siteurl). I tested the two apart on one lab site, with the same update package http://mysite.invalid/akismet.zip each time:

Site AddressWordPress AddressResult
http://localhost:8902http://localhost:8902A valid URL was not provided.
http://mysite.invalidhttp://localhost:8902cURL error 6: Could not resolve host: mysite.invalid
http://localhost:8902http://mysite.invalidA valid URL was not provided.

Only the Site Address matters for the skip. When it is the domain the server cannot resolve, the check is skipped and cURL fails alone.

What it is not#

  • It is not a PHP memory or time limit. Nothing here needed a change to either.
  • It is not a missing cURL extension. The text comes from cURL, so cURL works.
  • It is not a damaged plugin. The download stopped before any file was touched. For file errors after a good download, see could not create directory and incompatible archive.

For a safer update routine, read how to update plugins safely. Site Health can also show failed outgoing requests; see the Site Health guide.

Sources

  1. download_url() (WordPress Code Reference) · Returns a WP_Error on failure; fetches with wp_safe_remote_get()
  2. wp_http_validate_url() (WordPress Code Reference) · The address check: scheme, credentials, resolving host, private IPs, ports
  3. Editing wp-config.php: block external URL requests · WP_HTTP_BLOCK_EXTERNAL and WP_ACCESSIBLE_HOSTS
  4. libcurl error codes · 6 = host not resolved, 7 = could not connect
  5. WP_Upgrader::download_package() in wordpress-develop (6.8 branch) · Where the words Download failed. are added to the reason
  6. WP_Http::block_request() in wordpress-develop · Where the block setting and the allowed-hosts list are applied
  7. gethostbyname() (PHP manual) · Used by the address check; returns the host name unchanged when it cannot resolve
Newsletter

One email when something breaks or changes.

New plugins and re-tested guides, about twice a month. Never a sales pitch.