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.
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 fromdownloads.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
.tmpon 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 happened | Go to |
|---|---|---|
User has blocked requests through HTTP to the URL: and an address | A 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 … milliseconds | The 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 443 | The 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 received | The 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 Found | The 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 Unavailable | The 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 certificate | The 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.
- Browser
- DNS
- HTTPS
- CDN or firewall
- Web server (this error comes from here)
- PHP
- WordPress
- Database and files
What causes it
A line in wp-config.php blocks requests to other servers
SometimesWP_HTTP_BLOCK_EXTERNAL lets WordPress ask only its own site. Other servers are let through by naming them in WP_ACCESSIBLE_HOSTS. A list that names api.wordpress.org and leaves out downloads.wordpress.org lets WordPress hear about an update and stops it fetching one.
Fix: Find out whether the server can reach WordPress.org, or Install or update from a zip file, or Allow WordPress.org in wp-config.php
The server's firewall stops requests going out
CommonThe server may not open connections to other servers, or only to some. The request is dropped or refused before it reaches WordPress.org or the seller's server, and curl reports that it could not connect.
Fix: Find out whether the server can reach WordPress.org, or Install or update from a zip file, or Ask the host to open the way out
The server cannot look up the other server's name
SometimesWordPress looks the host name up before it asks for the file. When the server's own name lookup fails, or answers with an address inside a private network, WordPress refuses the address and never sends the request.
Fix: Find out whether the server can reach WordPress.org, or Install or update from a zip file, or Ask the host to open the way out
The download did not finish within 300 seconds
CommonWordPress gives one download 300 seconds. A large package on a slow connection between the two servers is still arriving when the time runs out, and what had arrived is thrown away.
Fix: Try the update again, one item at a time, or Install or update from a zip file
The server that holds a paid plugin or theme refused to hand it over
CommonA plugin or theme that updates from its maker's server is fetched from an address that server supplies. If the license has lapsed, is not entered or does not cover this site, that server can answer 401, 403 or 404 in place of the file.
Fix: Install or update from a zip file, or Check the license of a paid plugin or theme
The temporary folder named in wp-config.php is missing or closed
SometimesWordPress saves a download in its temporary folder before unpacking it. A WP_TEMP_DIR line in wp-config.php that names a folder which does not exist, or which the site may not write to, leaves the download nowhere to go.
The secure connection to the other server cannot be set up
RarePackages are fetched over HTTPS. If the handshake fails or the other server's certificate is not accepted, curl stops with error 35 or 60 before any of the file is sent.
Fix: Find out whether the server can reach WordPress.org, or Install or update from a zip file, or Ask the host to open the way out
WordPress.org or the seller's server is having trouble
RareThe other server answers with an error of its own, such as 500, 502 or 503, or answers too slowly. Nothing on your server is wrong, and the same update goes through later.
Fix: Try the update again, one item at a time, or Install or update from a zip file
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.
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.
Step 2: Ask WordPress to look again
Open Dashboard, then Updates, and click Check again.
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:
wp plugin update plugin-slugIf 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.
Step 1: Open Site Health
Open Tools, then Site Health, and stay on the Status tab.
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.phpis the cause, and the second one lists the hosts that are let through.Step 3: Know what Site Health leaves out
Its test asks
api.wordpress.organd no other server. Packages come fromdownloads.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:
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:
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.zipEach 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.
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.
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.
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.
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:
wp plugin install plugin.zip --forceFor a theme, in place of theme.zip:
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:
rm plugin.zipWordPress 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.
Step 1: Open wp-config.php
It is in the site's main folder. Download a copy before you change it.
Step 2: Find the list
Look for a line that defines
WP_ACCESSIBLE_HOSTS. If there is one, addapi.wordpress.organddownloads.wordpress.orgto it, separated by commas, and keep what is already there.Step 3: If there is no list, add one
Put this line above the comment that says to stop editing.
wp-config.phpdefine( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,downloads.wordpress.org' );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.
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:
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.
Step 1: Find the line
Open
wp-config.phpin the site's main folder, after downloading a copy of it, and look for a line that definesWP_TEMP_DIR.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.
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.
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:
wp config get WP_TEMP_DIRAnd this removes the line:
wp config delete WP_TEMP_DIRPHP 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.
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.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.
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.
Step 4: Ask WordPress to look again
Open Dashboard, then Updates, click Check again, and run the update.
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.
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.
Step 2: Ask three questions
- May PHP on this account open HTTPS connections, on port 443, to
api.wordpress.organddownloads.wordpress.org? - Does the server look both names up correctly?
- Is anything set to time out or filter outgoing requests?
- May PHP on this account open HTTPS connections, on port 443, to
Step 3: Add what the checks printed
If you ran the two
curlcommands 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.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.

