---
title: "How to fix \"Update failed: Download failed.\" in WordPress"
url: https://wpministry.co/errors/download-failed/
description: "WordPress could not fetch the package and stopped before changing anything. The words after \"Download failed.\" give the reason. Read them first."
lang: en-US
---

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

October 10, 2026

Tested on

WordPress 7.1.4, PHP 8.3.36

## 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 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**.

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

- ### A line in wp-config.php blocks requests to other servers
  Sometimes
  WP_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
  Common
  The 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
  Sometimes
  WordPress 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
  Common
  WordPress 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
  Common
  A 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
  Sometimes
  WordPress 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.
  Fix: Correct the temporary folder in wp-config.php
- ### The secure connection to the other server cannot be set up
  Rare
  Packages 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
  Rare
  The 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.

1. #### Step 1: Wait a few minutes
   If the package comes from WordPress.org, the WordPress.org Status Blog (https://status.wordpress.org/) 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 (https://wpministry.co/blog/how-to-safely-update-wordpress/) 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.4

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 (https://wpministry.co/blog/use-wp-cli-manage-wordpress/) 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.4

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 (https://wpministry.co/blog/how-to-safely-update-wordpress/) 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" (https://wpministry.co/errors/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 (https://wpministry.co/errors/missing-a-temporary-folder/).

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 (https://developer.wordpress.org/advanced-administration/upgrade/upgrading/).

**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.4

`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 Copy

   ```
   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

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" (https://wpministry.co/errors/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 (https://wpministry.co/errors/could-not-create-directory/), with a section on a disk that is full.

### 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" (https://wpministry.co/errors/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 (https://wpministry.co/errors/maximum-execution-time-exceeded/).

## More on this subject

- WordPress errors and troubleshooting: https://wpministry.co/topics/wordpress-troubleshooting/
- WordPress maintenance and care plans: https://wpministry.co/topics/wordpress-maintenance/
- Guide WordPress uptime monitoring: what a check sees and what it misses: https://wpministry.co/blog/wordpress-uptime-monitoring/
- Guide How to update the PHP version of a WordPress site: https://wpministry.co/blog/update-php-version-wordpress/
- Glossary term .htaccess: https://wpministry.co/glossary/htaccess/
- Guide Locked out of WordPress admin: find which lockout you have and get back in: https://wpministry.co/blog/locked-out-of-wordpress-admin/
- Glossary term Must-use plugin (mu-plugin): https://wpministry.co/glossary/must-use-plugin/
- Glossary term Permalink: https://wpministry.co/glossary/permalink/

## 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.

More about this work: One-time WordPress fix (https://wpministry.co/services/one-time-fix/)

May we measure how this site is used?

A yes notes the pages of this visit and loads Google Analytics. A no keeps and loads nothing. See the cookies page (https://wpministry.co/legal/cookies/).

If you say yes, we note the pages you look at during this visit and load Google Analytics. If you say no, nothing is kept and nothing is loaded. The site works the same either way. The cookies page (https://wpministry.co/legal/cookies/) has the details.

## Structured data

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://wpministry.co/#organization",
      "name": "WP Ministry",
      "url": "https://wpministry.co/",
      "logo": "https://wpministry.co/brand/logo.png",
      "address": {
        "@type": "PostalAddress",
        "streetAddress": "1309 Coffeen Ave STE 1200",
        "addressLocality": "Sheridan",
        "addressRegion": "WY",
        "postalCode": "82801",
        "addressCountry": "US"
      },
      "sameAs": [
        "https://www.linkedin.com/company/wp-ministry/",
        "https://x.com/wpministryco",
        "https://www.instagram.com/wpministryco/",
        "https://www.facebook.com/wpministryco",
        "https://www.tiktok.com/@wpministryco",
        "https://www.pinterest.com/wpministryco/",
        "https://www.youtube.com/channel/UCOZRuAukk5QSTRPG6BaHl3Q"
      ]
    },
    {
      "@type": "WebSite",
      "@id": "https://wpministry.co/#website",
      "name": "WP Ministry",
      "url": "https://wpministry.co/",
      "inLanguage": "en-US",
      "publisher": {
        "@id": "https://wpministry.co/#organization"
      }
    },
    {
      "@type": "TechArticle",
      "@id": "https://wpministry.co/errors/download-failed/#article",
      "headline": "How to fix \"Update failed: Download failed.\" in WordPress",
      "description": "WordPress could not fetch the package and stopped before changing anything. The words after \"Download failed.\" give the reason. Read them first.",
      "url": "https://wpministry.co/errors/download-failed/",
      "mainEntityOfPage": "https://wpministry.co/errors/download-failed/",
      "inLanguage": "en-US",
      "image": "https://wpministry.co/og/errors/download-failed.png",
      "author": {
        "@id": "https://wpministry.co/#organization"
      },
      "publisher": {
        "@id": "https://wpministry.co/#organization"
      },
      "datePublished": "2026-10-10T00:00:00.000Z",
      "dateModified": "2026-10-10T00:00:00.000Z"
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "position": 1,
          "name": "Home",
          "item": "https://wpministry.co/"
        },
        {
          "@type": "ListItem",
          "position": 2,
          "name": "Error fixes",
          "item": "https://wpministry.co/errors/"
        },
        {
          "@type": "ListItem",
          "position": 3,
          "name": "How to fix \"Update failed: Download failed.\" in WordPress"
        }
      ]
    }
  ]
}
```