Skip to content

How to fix "Update failed: Download failed." in WordPress

WordPress could not fetch the package for an update or an install, and stopped before it changed anything. The words after "Download failed." give the reason, such as a blocked request, a timeout, a refusal by the server that holds the file, or a temporary folder it cannot use. Read them first.

By
WP Ministry
Published
Tested on
WordPress 7.1.3, PHP 8.3.35

In short

  • Nothing was changed. The download failed before WordPress touched the plugin, the theme or its own files.
  • The words after "Download failed." are the reason. Read them before you try anything.
  • "User has blocked requests through HTTP" means a line in wp-config.php stopped the download. Add downloads.wordpress.org to WP_ACCESSIBLE_HOSTS.
  • "cURL error 28" is a timeout. WordPress gives one download 300 seconds.
  • "Unauthorized", "Forbidden" or "Not Found" is the answer of the server that holds the package. For a paid plugin or theme, check the license.
  • Uploading the zip yourself works while the server cannot reach WordPress.org, because an upload asks no other server for anything.

Before WordPress installs or updates anything, it downloads a zip file, the package, to the server. "Download failed." means that file did not arrive. WordPress stopped there. The plugin, the theme or WordPress itself is as it was a minute ago, and the site runs as before.

The message never comes alone. Right after it WordPress prints the reason it was given, and the reason tells you which fix on this page is yours.

text
Update failed: Download failed. User has blocked requests through HTTP to the URL: https://downloads.wordpress.org/plugin/classic-editor.1.7.0.zip.

Where WordPress prints it

  • On the Plugins and Themes screens. After you click "update now", the row shows "Update failed: Download failed." and the reason.
  • On the Add Plugins and Add Themes screens. After "Install Now", the card shows "Installation failed: Download failed." and the reason.
  • On Dashboard, then Updates. The line reads "An error occurred while updating", the name of the plugin, then "Download failed." and the reason. The screen still ends with "All updates have been completed." An update of WordPress itself prints "Download failed.:" with the reason after the colon, then "Installation failed."
  • In WP-CLI. It prints "Warning: Download failed." with the reason in quotes, then "Error: No plugins updated (1 failed)." or "Error: No plugins installed."

The Updates screen and WP-CLI also print "Downloading update from" and the address of the package, which shows which server was asked.

What WordPress does when it downloads

  • Where it asks. WordPress learns about updates from api.wordpress.org. It fetches the packages of plugins, themes and WordPress itself from downloads.wordpress.org. A plugin or theme that updates from its maker's server is fetched from the address that server supplies.
  • How long it waits. One download is given 300 seconds. There is no setting for that number.
  • Where the file goes. Into WordPress's temporary folder, under the package's name with a few random letters and .tmp on the end. A download that fails is deleted, so a failed attempt leaves nothing to clean up.

What the words after it tell you

What follows "Download failed."What happenedGo to
User has blocked requests through HTTP to the URL: and an addressA line in wp-config.php stops WordPress asking other servers, and the host in that address is not on its list of exceptions.Allow WordPress.org in wp-config.php
cURL error 28: Connection timed out after … millisecondsThe server never got through. Something on the way drops the request.Find out whether the server can reach WordPress.org
cURL error 7: Failed to connect to … port 443The connection was refused, or could not be made.Find out whether the server can reach WordPress.org
A valid URL was not provided.WordPress looks the host name up before it asks. The lookup failed on the server, or gave an address inside a private network.Find out whether the server can reach WordPress.org
cURL error 28: Operation timed out after … milliseconds with … out of … bytes receivedThe download began and was still running when the 300 seconds ran out.Try the update again, or install from a zip file
Unauthorized, Forbidden or Not FoundThe server that holds the package answered 401, 403 or 404. It would not hand the file over, or has no file at that address.Check the license of a paid plugin or theme
Internal Server Error, Bad Gateway or Service UnavailableThe other server answered 500, 502 or 503. The trouble is at its end.Try the update again
Destination directory for file streaming does not exist or is not writable.The temporary folder WordPress was told to use is missing, or closed to it.Correct the temporary folder in wp-config.php
cURL error 35 or cURL error 60, with words about SSL or a certificateThe secure connection to the other server could not be set up.Ask the host

The number after "cURL error" is curl's own code, and curl's documentation says what each means: 7 is "Failed to connect() to host or proxy", 28 is "Operation timeout", 35 is "A problem occurred somewhere in the SSL/TLS handshake", and 60 is "The remote server's SSL certificate or SSH fingerprint was deemed not OK". The examples in the table were read on a server with curl 8.14.1. Go by the number.

When the reason is only one or two words, such as "Not Found", it is the other server's answer to the request, in WordPress's name for the status code.

Where it goes wrong

A page request passes through each of these in turn. This one comes from the hosting account.

  1. Browser
  2. DNS
  3. HTTPS
  4. CDN or firewall
  5. Web server (this error comes from here)
  6. PHP
  7. WordPress
  8. Database and files

What causes it

How to fix it

Try the update again, one item at a time

  • Easy
  • Back up first
  • About 10 minutes

A timeout, or an error answered by the other server, can pass on its own. A reason that names wp-config.php, a folder or a license does not: go by the table.

  1. Step 1: Wait a few minutes

    If the package comes from WordPress.org, the WordPress.org Status Blog is where WordPress.org posts when its own systems are in trouble.

  2. Step 2: Ask WordPress to look again

    Open Dashboard, then Updates, and click Check again.

  3. Step 3: Update one item

    Take a backup first: How to safely update WordPress, plugins and themes shows how. Then tick one plugin and click Update Plugins. With one item at a time you see which download fails, and with which reason.

With WP-CLI, use the plugin's folder name in place of plugin-slug. The output names the address it downloads from, and the reason if it fails:

bash
wp plugin update plugin-slug

If the same item fails again with the same reason, it is not a passing fault. A package that keeps running out of time can be put on the server by hand, which the zip fix below covers.

To undo it: A download that fails changes nothing, so there is nothing to undo. An update that goes through is undone by restoring your backup.

Find out whether the server can reach WordPress.org

  • Takes care
  • No risk
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

Two places can stop a request on its way out: WordPress's own settings, and the server's network. These steps tell them apart.

  1. Step 1: Open Site Health

    Open Tools, then Site Health, and stay on the Status tab.

  2. Step 2: Look for two results

    "Could not reach WordPress.org" carries the line "Your site is unable to reach WordPress.org at", an IP address, "and returned the error:" and the reason. "HTTP requests are blocked" or "HTTP requests are partially blocked" means a line in wp-config.php is the cause, and the second one lists the hosts that are let through.

  3. Step 3: Know what Site Health leaves out

    Its test asks api.wordpress.org and no other server. Packages come from downloads.wordpress.org, so "Can communicate with WordPress.org" does not clear the download server.

Over SSH, from the folder WordPress is installed in, list the three settings in wp-config.php that bear on a download:

bash
wp config list WP_HTTP_BLOCK_EXTERNAL WP_ACCESSIBLE_HOSTS WP_TEMP_DIR

"Error: No matching entries found in 'wp-config.php'." means none of the three is set, and wp-config.php is not what stops the download.

Then ask both servers from the server's own command line, without WordPress in between:

bash
curl -sS --max-time 30 -o /dev/null -w '%{http_code}\n' https://api.wordpress.org/core/version-check/1.7/
curl -sS --max-time 30 -o /dev/null -w '%{http_code}\n' https://downloads.wordpress.org/plugin/akismet.zip

Each line should print 200. If the server cannot get out, curl prints its error in place of the number, with the same codes WordPress shows: curl: (6) Could not resolve host when the name lookup fails, (7) when it cannot connect, (28) when it times out.

  • Both print 200, and WP_HTTP_BLOCK_EXTERNAL is set: the server can get out and WordPress is told not to. Use the fix "Allow WordPress.org in wp-config.php".
  • Both print 200, nothing is set, and WordPress still fails: whatever stops WordPress does not stop the shell. Send the host both results.
  • curl fails too: the server's network is the cause. Go to "Ask the host".

If WP-CLI is new to you, How to use WP-CLI covers connecting over SSH and checking that it is installed.

To undo it: Nothing is changed. These steps only read.

Install or update from a zip file

  • Easy
  • Back up first
  • About 15 minutes
  • Steps tested on WordPress 7.1.3

An upload travels from your computer to the server, so the server asks no other server for anything. It works while every download fails. It is a way round and not a repair: the next update fails the same way until the cause is dealt with.

  1. Step 1: Get the zip

    A plugin or theme from WordPress.org has a "Download" button on its page in the directory. For one you paid for, download the current version from your account with the seller.

  2. Step 2: Take a backup

    An update from a zip is still an update. How to safely update WordPress, plugins and themes covers backing up first.

  3. Step 3: Upload it

    Open Plugins, then Add Plugin, click Upload Plugin, choose the zip and click Install Now. For a theme, open Appearance, then Themes, then Add Theme, then Upload Theme.

  4. Step 4: Replace the installed copy

    If the plugin is installed already, WordPress shows the two versions side by side and a button, "Replace current with uploaded". "Destination folder already exists" goes through that screen.

If the upload itself stops with "Missing a temporary folder.", PHP has nowhere to receive uploads, which is a fault of its own.

With WP-CLI, put the zip on the server over SFTP, then give its path in place of plugin.zip:

bash
wp plugin install plugin.zip --force

For a theme, in place of theme.zip:

bash
wp theme install theme.zip --force

--force replaces the copy that is installed. Without it, WP-CLI stops at "Destination folder already exists." when the plugin is there. Leave it off for a plugin that is not installed yet. Then delete the zip:

bash
rm plugin.zip

WordPress itself can be updated by hand as well, by replacing its files. WordPress's documentation sets the steps out under "Manual Upgrade" in Upgrading WordPress.

To undo it: Install the zip of the version you had in the same way, or restore your backup.

Allow WordPress.org in wp-config.php

  • Takes care
  • Low risk
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

define( 'WP_HTTP_BLOCK_EXTERNAL', true ); lets WordPress send requests to its own site and nowhere else. WP_ACCESSIBLE_HOSTS is the list of exceptions, separated by commas.

WordPress's documentation gives api.wordpress.org,*.github.com as its example of that list. With api.wordpress.org allowed and nothing more, WordPress hears about an update and offers it, and the download then fails, because packages come from downloads.wordpress.org.

  1. Step 1: Open wp-config.php

    It is in the site's main folder. Download a copy before you change it.

  2. Step 2: Find the list

    Look for a line that defines WP_ACCESSIBLE_HOSTS. If there is one, add api.wordpress.org and downloads.wordpress.org to it, separated by commas, and keep what is already there.

  3. Step 3: If there is no list, add one

    Put this line above the comment that says to stop editing.

    wp-config.php
    define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,downloads.wordpress.org' );
  4. Step 4: Add any other server the message names

    For a plugin that updates from its maker's server, the message prints the address that was blocked. Add the host name from that address to the same list.

  5. Step 5: Run the update again

    It can take a few seconds for the server to pick up the changed file.

A star stands for any subdomain: *.wordpress.org lets both servers through in one entry.

With WP-CLI, this sets the list in one command. It replaces the whole list, so include any hosts the line already had:

bash
wp config set WP_ACCESSIBLE_HOSTS 'api.wordpress.org,downloads.wordpress.org'

To undo it: Put the line back as it was, from the copy you kept.

Correct the temporary folder in wp-config.php

  • Takes care
  • Low risk
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

Left to itself, WordPress picks its temporary folder by trying PHP's temporary folder, then PHP's upload folder, then wp-content, and takes the first it can write to. A line in wp-config.php that defines WP_TEMP_DIR overrides all of that, and it is the one choice WordPress does not check. A path that was right on a previous server and does not exist on this one gives this reason on every download.

  1. Step 1: Find the line

    Open wp-config.php in the site's main folder, after downloading a copy of it, and look for a line that defines WP_TEMP_DIR.

  2. Step 2: Look for the folder it names

    In your host's file manager or over SFTP, go to that path. See whether the folder exists.

  3. Step 3: Remove the line, or correct it

    If the folder is not there and nobody asked for the line, delete the line. WordPress then chooses a folder itself. If the host asked for the line, correct the path to a folder that exists and that the site may write to. The host can say which.

  4. Step 4: Run the update again

    It can take a few seconds for the server to pick up the changed file.

With WP-CLI, this prints the folder the line names:

bash
wp config get WP_TEMP_DIR

And this removes the line:

bash
wp config delete WP_TEMP_DIR

PHP has a temporary folder of its own, where uploads from your browser land. It is a different setting, and "Missing a temporary folder" covers it.

A temporary folder with no room left reads differently. The download appears to finish, and the failure comes one step later, as "The package could not be installed." If the download goes through and the next step fails with "Could not create directory.", that message has a page too, with a section on a disk that is full.

To undo it: Put the line back as it was, from the copy you kept.

Check the license of a paid plugin or theme

  • Easy
  • No risk
  • About 15 minutes

"Unauthorized", "Forbidden" and "Not Found" are answers. The request reached the other server, and that server declined to send the file. A package from WordPress.org needs no license, so there the thing to do is wait and try again. For a plugin or theme that updates from its maker's server, check the license first.

  1. Step 1: See which server was asked

    Run the update from Dashboard, then Updates. The line "Downloading update from" shows the address. If it is not downloads.wordpress.org, the package comes from the seller.

  2. Step 2: Check the license in your account with the seller

    See that it has not expired and that it covers this site. Sellers differ in how many sites a license covers and how a site is tied to it, so if the site has moved to a new address, see whether the license still names it.

  3. Step 3: Enter the key again on the site

    Open the plugin's or theme's own license screen and enter the key again, or deactivate and reactivate the license there. Where that screen is differs from product to product. The seller's documentation says.

  4. Step 4: Ask WordPress to look again

    Open Dashboard, then Updates, click Check again, and run the update.

  5. Step 5: Or use the zip

    Download the current version from your account and install it with the zip fix above.

"Update package not available." is a close relative of this message: WordPress was told of an update and given no address to fetch it from. For a paid plugin or theme, check the license in the same way.

To undo it: Nothing on the site is changed until the update itself runs.

Ask the host to open the way out

  • Easy
  • No risk
  • About 15 minutes

A firewall rule, a name lookup that fails and a secure connection that cannot be set up are all settled on the server, by whoever runs it.

  1. Step 1: Copy the whole message

    Send the full line with its reason, the time it happened, and the name of the plugin or theme. The reason is what support will go by.

  2. Step 2: Ask three questions

    • May PHP on this account open HTTPS connections, on port 443, to api.wordpress.org and downloads.wordpress.org?
    • Does the server look both names up correctly?
    • Is anything set to time out or filter outgoing requests?
  3. Step 3: Add what the checks printed

    If you ran the two curl commands in "Find out whether the server can reach WordPress.org", paste their output. It shows the host whether the fault is in the network or only in PHP.

  4. Step 4: Update from a zip while you wait

    The zip fix above does not need the server to reach anyone.

To undo it: Nothing on the site is changed.

When to get help

If the reason points at the server's network, the host says nothing is blocked, and downloads still fail, someone has to read the server's side of it, which means its firewall rules, its name lookups and its PHP error log. That takes access to the server. The same is true when one plugin fails every time and the others update.

Common questions

Did the failed update break anything?

No. The download is the first step, and WordPress stops there. The installed copy is still in place and still active. If the plugin was active, visitors may have seen the maintenance notice while WordPress waited for the download, because the dashboard turns maintenance mode on before it downloads and off when it is done. A notice that stays is a different fault: see "Briefly unavailable for scheduled maintenance".

Why does WordPress now say the plugin is up to date?

After an update is tried from the dashboard, WordPress clears what it knew about available updates and asks api.wordpress.org again. If that request is stopped as well, it has no answer, so the update notice disappears, and trying again gets "The plugin is at the latest version." WP-CLI does the same and prints "Success: Plugin already updated." The update is still there. The notice comes back once the server can reach api.wordpress.org.

Is "An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration." the same fault?

It has the same causes, one step earlier. WordPress prints it when it cannot reach api.wordpress.org to search for a plugin or read its details, before there is any package to download. The sentence "WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator." is raised at the same moment as a PHP notice or warning, so it shows up where PHP's messages go, in the error log or the debug log. WordPress raises it whenever that request fails, whatever stopped it, so it does not by itself mean that the secure connection is at fault.

Can I raise the 300 seconds?

Not with a setting. The number is written into WordPress, and neither wp-config.php nor the dashboard changes it. A package too large or too slow to arrive in that time can be uploaded as a zip instead. PHP's own limit on how long a request may run is a different thing, with a page of its own.

More on this subject

Would you rather we fixed it?

Quick Fix is $49. One issue, one site, up to about an hour. No fix, no fee. 30-day warranty. It starts with a free diagnosis.