An automated WordPress update has failed to complete: how to safely recover

WordPress emailed you to say the automatic update did not finish. The site might be fine, the site might be locked in maintenance mode, or the site might be running the new version with cached old code. This article walks the safe recovery path: verify the site state, clear the .maintenance file, work through the five real causes, and confirm the update actually completed.

You opened your inbox and found an email with the subject "[your site name] An automated WordPress update has failed to complete - please attend to the issues", or a similar admin notice in wp-admin. The message is unsettling. It does not tell you whether the site is up, whether visitors see anything, or what to do first. The honest first step is to confirm what is actually broken, and the honest second step is to recover the right thing in the right order. This article walks both.

What the email or admin notice actually means

WordPress sent that email through the auto_core_update_email hook, which has shipped since WordPress 3.7 in 2013. The email type behind your message is one of three: success (the update worked), fail (a non-critical step failed before file copying began, often a download problem), or critical (a severe failure during file copying, such as a disk full error or a failed rollback). The fail and critical types are the ones that produce the "failed to complete" subject line.

A fail is recoverable by retrying. A critical is not. WordPress sets an internal flag and stops attempting background updates until you intervene, because a critical failure suggests the site is in a state where another automatic attempt would make things worse.

First, check whether your site is actually up

Before you change anything, find out what visitors see right now. The email does not tell you. Some failures leave the site running the old version perfectly. Others lock it in maintenance mode. Open the homepage in a private browser window and look at three things.

  • The page renders normally. The update aborted before it could break anything. The site is on the old version. Recovery is calm and you have time.
  • The page shows "Briefly unavailable for scheduled maintenance. Check back in a minute." A .maintenance file is left behind in the WordPress root. Visitors are getting a 503. This needs the immediate fix below. The full mechanics live in briefly unavailable for scheduled maintenance: how to fix a stuck WordPress update.
  • The page shows "There has been a critical error on this website". The update completed file replacement but left the site with broken code. Treat the email as secondary and follow there has been a critical error on this website first.

Open wp-admin in a separate tab. If it loads, log in and go to Dashboard > Updates. WordPress shows the current state and whether the update is genuinely outstanding or finished without telling the email handler. The version number at the bottom of any admin page is the source of truth for which version actually loaded.

Common causes, ordered by likelihood

After many of these incidents, the order is consistent.

  1. Insufficient disk space, often in wp-content/upgrade-temp-backup/. WordPress 6.3 introduced this directory so it can roll back failed manual plugin and theme updates by relocating the previous version with move_dir(). A weekly WP-Cron task cleans it up, but on a low-quota plan or a busy update cadence, it can fill the disk before the cron runs. WordPress trips a critical email when the new package cannot be unpacked because the disk is full.
  2. File permissions block direct updates. WordPress decides how to write files via get_filesystem_method(). The precedence is direct, then ssh2, then ftpext, then ftpsockets. If the PHP user does not own the WordPress files, direct is rejected and WordPress falls back to a method that needs credentials it does not have during an automatic update. The update aborts before any files are touched.
  3. PHP timeout or memory exhaustion mid-update. Shared hosting plans with tight max_execution_time (often 30 to 60 seconds) or low memory_limit (often 128M) can kill the PHP process while it is still unpacking a release zip or running database upgrade routines. The update partially completes and you get an email.
  4. Network failure during the package download. The download from downloads.wordpress.org was interrupted, the host blocked the outbound connection, or the file integrity check failed. WordPress detected the bad package and aborted before applying it. This is a fail type, not a critical, and it usually retries successfully on the next cron tick.
  5. OPcache serving stale bytecode after the update. The files were replaced cleanly, but PHP's OPcache still has the old bytecode in memory. The site loads, but it is running a mix of old and new code, which is unstable. WordPress tries to invalidate OPcache via wp_opcache_invalidate() (since WordPress 5.5) and wp_opcache_invalidate_directory() (since WordPress 6.2), but on hosts where the PHP process the cron job runs in is different from the FPM pool serving the site, those calls do not invalidate the right cache.

The diagnosis below tells you which one applies before you change anything.

Diagnose before you fix

You want signal, not noise. Run these checks in order. Stop at the first one that returns a clear answer.

Check 1: is the site in maintenance mode? In your hosting panel's file manager (cPanel, DirectAdmin, Plesk, or your host's equivalent), open the WordPress root, the directory that contains wp-config.php. Turn on Show Hidden Files in the file manager settings. If a file called .maintenance is present, the site is locked. The expected fix is the next section.

Check 2: how full is the disk? In your hosting panel, find the disk usage view (cPanel: Statistics > Disk Usage, DirectAdmin: Disk Usage, Plesk: Hosting Services > [domain] > Statistics). If you are at 95% or higher, that is your cause. Then specifically look at wp-content/upgrade-temp-backup/: in the file manager, navigate there and check whether it contains old plugins/ or themes/ subdirectories left behind from previous failed updates. Site Health in wp-admin exposes a test for the temporary backup directory that flags this case.

Check 3: what does the WordPress debug log say? If WP_DEBUG_LOG is on (set in wp-config.php), open wp-content/debug.log from your hosting panel's file manager. The last entries from the time of the update tell you exactly what failed. A line like Failed to copy ... points at permissions or disk space. A line like Maximum execution time of 30 seconds exceeded points at the PHP timeout. If WP_DEBUG_LOG is not yet on, see enable and read the WordPress debug log to switch it on safely.

Check 4: what does your hosting error log say? Every modern hosting panel exposes the PHP error log for your site. cPanel calls it Errors, DirectAdmin Error Log, Plesk Logs. Look for entries from the time the update was attempted. PHP fatals, segfaults, and out of memory killers all appear here even when the WordPress debug log is silent.

Check 5: does Site Health flag anything? Open Tools > Site Health in wp-admin. The Status tab tests for the writable temporary backup directory, the loopback request, and the cron health. Any failed tests there are extra signal.

You now know which cause you are dealing with. Move on to the matching fix.

The immediate fix: clear the .maintenance file

If your site is showing the maintenance message, deal with that before anything else. Visitors are getting a 503 and they do not care why.

  1. In your hosting panel's file manager, navigate to the WordPress root (the folder that holds wp-config.php).
  2. Turn on Show Hidden Files if you have not already.
  3. Right-click .maintenance and choose Delete. Confirm.
  4. Reload your homepage in a private browser window.

You will know it worked when the homepage loads normally, or when it shows a different error. A different error is good news: it means the maintenance mask has lifted and you can now see and fix the real problem underneath.

The full diagnostic context for this file lives in briefly unavailable for scheduled maintenance: how to fix a stuck WordPress update. If .maintenance reappears within seconds of deletion, a scheduled auto-update is retrying and failing repeatedly, and the cause sections below are where to look next.

Cause A: insufficient disk space (upgrade-temp-backup full)

This is the most common critical failure on smaller hosting plans. Old failed-update backups in wp-content/upgrade-temp-backup/plugins/ and wp-content/upgrade-temp-backup/themes/ accumulate, the disk runs out of headroom for the new release zip, and the unpack step fails halfway through.

Fix it in three steps.

  1. Free space first. In your hosting panel's file manager, navigate to wp-content/upgrade-temp-backup/. Empty both the plugins/ and themes/ subdirectories. The weekly WP-Cron task that normally handles this clearly did not, so do it manually. Also empty wp-content/upgrade/ if it has stale files.
  2. Verify free space is sufficient. As a rough rule, you need at least the size of the WordPress install plus 200 MB free for a core update to complete. On a 5 GB plan, that means staying under 4.5 GB used.
  3. Retry the update. From wp-admin, go to Dashboard > Updates and click Update Now. Or wait for the next WP-Cron tick if the failure was on an automatic update.

You will know it worked when the Updates page shows the new version number and the homepage loads with the updated WordPress version visible in the dashboard footer.

If you keep running out of space, the disk quota is the underlying problem. A WordPress core update needs around 60 to 80 MB of free working space, and a major plugin update can need much more. If your plan does not give you headroom, you will keep hitting this every release cycle.

Cause B: file permissions block direct updates

get_filesystem_method() rejected the direct method because the PHP process and the WordPress files have different ownership. A typical sign in your hosting error log is a line like "Could not create directory" or "failed to open stream: Permission denied". Visitors might still see the WordPress login screen prompt for FTP credentials when you trigger a manual update from the dashboard.

The full diagnostic walk-through and fix lives in WordPress asking for FTP credentials on plugin install. The summary for this scenario:

  • On most managed and shared hosts, the fix is in the hosting panel, not in wp-config.php. cPanel: File Manager > Permissions or contact support to align ownership. Plesk: Hosting & DNS > Hosting Settings for the FTP user, or Permissions Recalculation tooling. DirectAdmin: open the user's settings and check the PHP execution method.
  • If you have shell access, chown -R www-data:www-data /var/www/yoursite.com/public (adjust to your PHP user and path) makes the files owned by the PHP process. After that, direct is selected and updates run without prompts.
  • The wp-config.php shortcut is define( 'FS_METHOD', 'direct' );, but only define it after confirming the PHP user can write the files. Defining it without fixing ownership turns the friendly prompt into a silent failure.

You will know it worked when the next manual update from the dashboard shows the install progress without the FTP credentials form, and the email does not arrive again.

Cause C: PHP timeout or memory exhaustion mid-update

The update is running, the package is being unpacked, and PHP is killed before it finishes. WordPress emails you because it cannot complete the post-update cleanup steps. The site might still be partially updated.

Look at the hosting panel error log for one of these signatures:

  • PHP Fatal error: Maximum execution time of N seconds exceeded
  • PHP Fatal error: Allowed memory size of N bytes exhausted
  • The PHP process was OOM-killed (the log line will not always be in PHP's log; it shows up in the system journal on Linux hosts).

Raising these limits depends on your hosting panel.

  • cPanel: open MultiPHP INI Editor, switch to Editor Mode, and raise max_execution_time to 300 and memory_limit to 512M for your domain.
  • DirectAdmin: under Domain Setup > [your domain] > PHP Settings, the same two values are exposed.
  • Plesk: Websites & Domains > [your domain] > PHP Settings, edit memory_limit and max_execution_time.
  • No GUI access: edit wp-config.php and add define( 'WP_MEMORY_LIMIT', '512M' ); for memory. The execution time cap usually has to be raised at the server level, but set_time_limit( 300 ); near the top of wp-config.php works on hosts that allow it.

You will know it worked when the next update completes without the email, the dashboard footer shows the new version number, and Tools > Site Health has no orange or red flags. If the host caps you below 60 seconds and refuses to budge, that is a signal to reconsider the hosting plan. The full context lives in allowed memory size exhausted in WordPress and maximum execution time exceeded in WordPress.

Cause D: network failure during the package download

The package download from downloads.wordpress.org was incomplete or the integrity check rejected the bytes received. WordPress aborted before it touched any files. This is a fail type, not critical, and it is the most benign cause.

Diagnosis is short. In the hosting panel error log, look for lines like "Could not write file" near a download URL, or DNS errors mentioning downloads.wordpress.org. From the Tools > Site Health screen, the Loopback test or the HTTP requests test sometimes flags the underlying restriction.

The fix is almost always to retry. WP-Cron will attempt the update again at the next tick, and most of these failures resolve on the second try because the network glitch was transient.

If retries keep failing, the host is blocking outbound HTTPS or has DNS issues that affect WordPress.org. Open a ticket with the host and ask them to confirm that PHP on your account can reach https://api.wordpress.org/ and https://downloads.wordpress.org/. The expected outcome is that those endpoints return HTTP 200 from the host's perspective.

You will know it worked when the next email is the success type, or when the Updates page shows the new version after the cron tick.

Cause E: OPcache serving stale bytecode after the update

The files updated cleanly. The footer in wp-admin shows the new version number. But weird errors appear on the front end: undefined functions, missing methods, fatals on previously-working pages. The site is running the new code in some places and the old bytecode in others, because PHP's OPcache did not see the file changes.

This is rare on default hosting setups but common in two scenarios:

  • The PHP process running WP-Cron is a separate FPM pool from the one serving web requests. WordPress called wp_opcache_invalidate() inside the cron worker, which invalidated the cron worker's OPcache, but the web pool kept the old bytecode.
  • opcache.validate_timestamps is set to 0 for performance, which tells PHP to never check whether the source file has changed. That setting is correct on production, but it means OPcache only refreshes when the pool restarts.

The fix is to flush OPcache for the right pool.

  • cPanel or DirectAdmin: open Select PHP Version (or MultiPHP Manager), and click Restart PHP if the option exists. Some hosts expose a dedicated OPcache Reset button.
  • Plesk: Websites & Domains > [your domain] > PHP Settings, save without changing anything. Plesk restarts the FPM pool on save, which flushes OPcache.
  • No GUI option: drop a file called opcache-reset.php in the WordPress root containing exactly <?php if ( function_exists( 'opcache_reset' ) ) { opcache_reset(); echo 'flushed'; }, load it once in your browser, and delete it immediately. Leaving the file in place is a security hazard.

You will know it worked when the front-end errors disappear, the dashboard pages render without notices, and php -i | grep opcache (if you have shell access) shows opcache_reset() ran successfully.

Verify the update actually completed

After applying the right fix, confirm three things before you call the incident closed.

  • The version number is right. In wp-admin, every page footer shows the running WordPress version. Compare it to the version mentioned in the failed-update email. They should match.
  • The front end loads from a private browser window. Logged-in views can be misleading because of admin-only behavior. A private window shows what visitors actually see.
  • Site Health passes. Tools > Site Health > Status. The temporary backup directory test, the cron test, and the loopback test should all be green. Any orange flag is a hint that the underlying cause is not fully resolved.

If all three pass, the update is complete. If the email arrives again on the next cron tick, the underlying cause is still active and you go back to the diagnosis section.

When to escalate

If you have worked through the diagnosis and the matching fix and the site is still not on the new version, or the email keeps arriving, hand the problem to your host or a WordPress specialist with a ready bundle. The first hour of any incident response is collecting context, and you can save it.

Collect before you ask:

  • The exact text of the failed-update email, including the WordPress version it tried to install.
  • Your current WordPress version (from any wp-admin page footer).
  • The PHP version (from your hosting panel under PHP settings).
  • The disk space you currently have free, and specifically the size of wp-content/upgrade-temp-backup/ if it exists.
  • The last 50 lines of wp-content/debug.log from the time of the update.
  • The last 50 lines of the hosting panel error log for the same window.
  • The hosting plan tier and any quotas or limits the panel exposes (memory, execution time, disk).
  • A list of the diagnostic checks and fixes you already tried, in order, and what changed each time.
  • Whether the homepage loads now, whether wp-admin loads now, and what each one shows in a private browser window.

A specialist can usually pinpoint the cause in 20 to 30 minutes with that bundle. Without it, the same job takes most of an afternoon.

How to make this less likely next time

You cannot prevent every transient failure, but you can make recovery boring instead of stressful.

  • Keep at least 500 MB of free disk space at all times. This avoids the most common critical email and the silent corruption that comes with it. If your plan does not let you stay that headroomed, the plan is the problem.
  • Schedule a weekly cleanup of wp-content/upgrade-temp-backup/. WordPress tries to do this itself, but only weekly and only when WP-Cron is healthy. A simple WP-Cron health check (open Tools > Site Health monthly) is enough.
  • Test backups before you need them. A backup that has never been restored is not a backup. Even one practice restore on a staging copy turns the recovery path from theory to muscle memory. The full setup is in how to restore WordPress from a backup.
  • Keep the admin email on an inbox you actually read. The email this article is about is your earliest warning, and it is worth nothing if it lands somewhere you do not check.
  • Update during low-traffic hours. Any incident is easier to recover from when nobody is filling the cart, submitting forms, or loading the contact page in the middle of it. WordPress lets you control the auto-update window with the auto_update_core_dev and related filters, or with a managed host that schedules updates for you.
  • For mission-critical sites, take a backup before WP-Cron triggers an auto-update. Most managed hosting platforms can fire a backup in the hour before scheduled core or plugin updates. If yours does not, schedule one yourself.

The "automated update has failed to complete" email is alarming, but the failure modes are limited and the fixes are well-trodden. The honest version is that most of these incidents are either disk space, file permissions, or PHP limits, and identifying which one applies is half the work.

Want this to stop being your problem?

If outages or errors keep repeating, the fix is often consistency: updates, backups and monitoring that don't get skipped.

See WordPress maintenance

Search this site

Start typing to search, or browse the knowledge base and blog.