We may earn a referral fee at no additional cost to you when you shop through the links on this page.
A plugin or theme update stops with Could not move the old version to the upgrade-temp-backup directory, and sometimes the plugin then vanishes from your Plugins list. The cause is almost always ownership: a second account, such as root, an SSH or FTP login, or a deploy script, owns files that the user PHP runs as can’t change.
Quick Fix: Find Which Two Users Are Involved
Run these from your WordPress root, the folder that holds wp-config.php. First, see who owns the backup folder and anything inside it:
ls -ld wp-content/upgrade-temp-backup wp-content/upgrade-temp-backup/*
drwxr-xr-x 3 root root 4096 Nov 3 23:17 wp-content/upgrade-temp-backup
drwxr-xr-x 2 root root 4096 Nov 3 23:17 wp-content/upgrade-temp-backup/plugins
Then find the user PHP runs as. This covers Apache with mod_php and PHP-FPM:
ps -eo user,comm | grep -E 'apache2|httpd|php-fpm' | sort -u
root apache2
www-data apache2
Ignore the root line, which is the parent process. If php-fpm processes appear, their user is PHP’s (Apache’s own user only matters with mod_php); on a stock Ubuntu or Debian server with one site, it’s www-data. Where several sites each run their own PHP-FPM pool (managed hosts, multi-site servers), ps lists several users, so ask the site itself: upload one image in Media → Add New, then list the newest files in this month’s uploads folder (this assumes the default uploads location, organised into year and month folders). WordPress wrote that file as the PHP user, even on a site migrated from somewhere else:
ls -lt wp-content/uploads/$(date +%Y)/$(date +%m) | head -n 3
total 4
-rw-rw-r-- 1 www-data www-data 70 Nov 3 23:17 pixel.png
On a server you administer, give the backup folder to that user when someone else owns it, replacing www-data:www-data with the user you just found and its group (usually the same name; id -gn followed by the user name prints it):
sudo chown -R www-data:www-data wp-content/upgrade-temp-backup
If you have no sudo but your SSH account shares a group with PHP, make the folder group-writable instead, as shown in the second-account section. Between updates, upgrade-temp-backup/plugins should be empty; a plugin folder sitting in it is a leftover, and if another account owns it, it will break that plugin’s next update, covered in the vanished-plugin section. Then retry the update from Dashboard → Updates. If it now fails with some files could not be copied, the plugin’s own folder has the same owner problem, covered in the copy-error section.
If the Plugin Disappeared After the Failed Update
The worst version of this error takes the plugin with it. WordPress may report that the plugin has been deactivated due to an error: Plugin does not exist, and it drops out of the Plugins list even though its folder is still in wp-content/plugins.
I reproduced how that happens. When a plugin’s files belong to another account, its first update succeeds, but a copy of the plugin owned by the other account stays behind in upgrade-temp-backup/plugins, because PHP can’t delete it. On the next update of that plugin, the update fails with this error partway through: only the plugin’s subfolders survive, without its main file, so WordPress no longer lists the plugin. While that remnant exists, a reinstall only reports that the plugin is already installed.
To recover, move both the leftover copy and the remnant out of the way as root, replacing plugin-name with the plugin’s folder name. Moving rather than deleting keeps a copy until the reinstall works; for a premium plugin that isn’t on WordPress.org, have its zip file ready first:
sudo mkdir -p /root/plugin-recovery
sudo mv wp-content/upgrade-temp-backup/plugins/plugin-name /root/plugin-recovery/plugin-name-backup
sudo mv wp-content/plugins/plugin-name /root/plugin-recovery/plugin-name-remnant
Then reinstall it from Plugins → Add New (or upload the zip), or from the shell as the PHP user:
sudo -u www-data wp plugin install plugin-name --activate
In my test, the plugin comes back, still active. Once the site works, delete /root/plugin-recovery. Fix the ownership with the quick fix first, or the same thing happens on its next update.
No Shell Access? Fix It From Your Host’s Panel
On shared hosting this error usually shows up in wp-admin with no terminal in sight. When the backup folder itself is the problem, Tools → Site Health shows a critical item titled Plugin temporary backup directory exists but is not writable, explaining: The wp-content/upgrade-temp-backup/plugins directory exists but is not writable. (A leftover plugin copy or plugin files owned by another account don’t trigger it.) You can still clear it from a browser:
- Clear the folder. Open
wp-content/upgrade-temp-backup/pluginsin your host’s file manager (cPanel File Manager, Plesk Files) or an SFTP client, with no update running. If it andupgrade-temp-backup/themes(when present) are both empty, deleteupgrade-temp-backup; WordPress recreates it on the next update as the user PHP runs as. If a plugin or theme folder is inside, it may be the only complete copy, so download or rename it before removing anything. If a plugin vanished, rename its folder inwp-content/plugins(toplugin-name-old, say) rather than deleting it, have the zip ready if it’s a premium plugin, reinstall it, and remove the old folder once the site works. - Use the panel’s permissions reset. On Cloudways, the Reset Permission option in Application Settings resets file and folder permissions for the application’s
public_html. - If the file manager can’t delete it, the folder belongs to an account you can’t touch. Ask your host to make
wp-content/upgrade-temp-backupandwp-content/pluginsowned by, or group-writable for, the account PHP runs as on your site.
Why WordPress Needs upgrade-temp-backup
Since WordPress 6.3, a manual plugin or theme update first moves the installed version into wp-content/upgrade-temp-backup/plugins/ (or themes/). If the new version fails to install, WordPress moves the old one back, so the site keeps running. Once the update completes, the backup is deleted. WordPress tries a rename first and falls back to copying the files with copy_dir(). The error appears when both fail.
Both fail when the user doing the update can’t write where it needs to. Whichever account runs the first update creates upgrade-temp-backup/plugins, typically with mode 755, so only that account can write to it. A rename also needs one permission that people miss when they check only the parent folders. The Linux rename(2) manual lists this as a permission error: oldpath is a directory and does not allow write permission (needed to update the .. entry). Moving a plugin’s folder therefore needs write access to that folder itself. And when cleanup fails the same way, the backup is left behind, which is the vanished-plugin case above.
Which Setups Run Into It
In every thread I read and every case I reproduced, the cause was ownership, and the usual way that goes wrong is two accounts touching the same files. These are the common ones, and the owner you’ll see in the ls -ld output:
| Setup | The two accounts | Owner you’ll see |
|---|---|---|
| Your own server, WP-CLI run as root | root and the PHP user (www-data) | root |
| Cloudways | The master SSH/SFTP user and the application user PHP runs as | The master user, mode 755 |
| Bitnami WordPress (AWS Lightsail and others) | bitnami (SSH login) and daemon | bitnami or daemon |
| Plesk with PHP as an Apache module | The subscription’s system (FTP) user and apache | The subscription user |
Bitnami’s own documentation sets WordPress files to the bitnami user and daemon group, while plugins installed from wp-admin end up owned by daemon. On Plesk, PHP-FPM and FastCGI run PHP as the subscription’s own user, so only the Apache-module mode splits the accounts. Any other route that copies files in as a different user, such as a deploy script or an FTP upload, creates the same split.
If You Ran WP-CLI as Root
WP-CLI refuses to run as root by default, because it loads all of your site’s code with root’s permissions; --allow-root overrides that, and every update it runs leaves root-owned files behind, starting with the backup folder. After one root update, the next update run as the PHP user fails like this:
Warning: Could not move the old version to the upgrade-temp-backup directory.
Plugin update failed.
The quick fix’s chown clears the folder. Plugins updated as root are root-owned too, so list everything root owns under wp-content:
sudo find wp-content -user root
Then give each listed folder back to the PHP user:
sudo chown -R www-data:www-data wp-content/plugins/plugin-name
If a Second Account Shares the Files
On hosts that give you an SSH or SFTP account next to PHP’s user, the owner can open the folder to its group without sudo. That only helps when the folder’s group (the fourth column of the ls -ld output) is a group PHP’s user belongs to, as on Cloudways and Bitnami. If you have SSH as that account, run this from the WordPress root:
chmod -R g+w wp-content/upgrade-temp-backup
WordPress’s file permissions guide accepts this setup: if all ftp users are known and trusted, i.e., not a shared host, then assigning group writable may be appropriate.
Check the result with ls -ld. A + after the permissions (drwxrwxr-x+) means the folder also carries an access control list, which Cloudways adds to some folders for its monitoring user. Then chmod is not enough, because of how the acl(5) manual maps permission bits: If the ACL has an ACL_MASK entry, the group permissions correspond to the permissions of the ACL_MASK entry. In my test, chmod -R g+w on such a folder showed 775 but left the owning group read-only, and the update still failed. Set the group’s own entry as well:
setfacl -R -m g::rwx wp-content/upgrade-temp-backup
Cloudways is a clear example. Its master credentials have SSH and SFTP access to every application on the server, while application credentials are limited to one application. On my own Cloudways server, every WordPress application’s PHP-FPM pool runs as that application’s own user, and each application’s wp-config.php sets the modes WordPress uses from the current umask:
grep FS_CHMOD wp-config.php
define('FS_CHMOD_DIR', (0775 & ~ umask()));
define('FS_CHMOD_FILE', (0664 & ~ umask()));
An SSH session’s umask is usually 022, which turns 0775 into 755, so a WP-CLI update run as the master user leaves a folder PHP can’t write to. One of my own sites was in exactly this state.
A common SSH workaround is wp plugin install plugin-name --force, which overwrites the installed plugin without prompting. It gets past the error because an install never moves the old version into upgrade-temp-backup, but it leaves the plugin’s folder owned by your account with mode 755 and its files 644, so the next update from wp-admin fails with a different error. If you use it, finish with:
chmod -R g+w wp-content/plugins/plugin-name
If that folder shows a + in ls -ld, follow it with setfacl -R -m g::rwx wp-content/plugins/plugin-name, as above.
When the Error Becomes “Some Files Could Not Be Copied”
Once the backup folder is fixed, updating a plugin that another account installed can still fail:
Warning: The update cannot be installed because some files could not be copied. This is usually due to inconsistent file permissions. "classic-widgets.php, readme.txt, LICENSE.md"
Plugin update failed.
This time it’s the plugin’s own files, owned by the other account at 755 and 644, that PHP can’t overwrite. Apply the same fix to that plugin’s folder: chmod -R g+w wp-content/plugins/plugin-name when the accounts share a group (plus setfacl -R -m g::rwx on the same folder if it shows a +), or sudo chown -R www-data:www-data wp-content/plugins/plugin-name on your own server. If WordPress asks you for FTP details instead of showing an error, that’s the same mismatch with a different symptom, covered in WordPress asking for FTP credentials. For update failures with other causes, see fixing Some Plugins Have Failed to Update.
Why 775 Works for Some People and 777 Is the Wrong Fix
The most common forum advice is to create upgrade-temp-backup yourself and set it to 775. That helps only when PHP’s user is in the folder’s group and every plugin folder below it is group-writable too. In my test, a plugin whose top folder was 775 but whose subfolders were 755 updated once and then left the stale copy behind, so the error returned on its next update. Run the quick fix’s checks instead of guessing a mode.
The other common advice, chmod -R 777 wp-content, works because 777 grants read, write and execute access to every user on the server, which is exactly the problem. WordPress’s own file permissions guide is blunt: No directories should ever be given 777, even upload directories.
chown), or add group write (g+w) when two trusted accounts share a group. Neither opens your files to every other user on the server, which is what 777 does. If ls -l output and octal modes are new to you, see checking and changing file permissions in Linux. The same ownership problem one level up shows as Could not create the upgrade-temp-backup directory, meaning PHP can’t write to wp-content itself. The same owner problem on the uploads folder breaks media uploads, as covered in the uploads folder set to 755 guide.
Stop It Coming Back
The usual trigger is a second account running an update or copying files in, so control which account that is:
- On your own server, run WP-CLI as the PHP user rather than as root:
sudo -u www-data wp plugin update --all. - When a second account shares PHP’s group, check whether
wp-config.phpderives its modes from the umask (grep FS_CHMOD wp-config.phpshowsumask(), as on Cloudways). If it does, setumask 002in your SSH session before running WP-CLI. In my test, the second account’s updates then created folders at 775 and files at 664, and PHP’s user updated those same plugins afterwards without errors. If it doesn’t, runchmod -R g+won what you changed afterwards, plussetfacl -R -m g::rwxwherels -ldshows a+. - After any upload or deploy from another account, run
ls -ldon the plugin, theme or folder it changed, as in the quick fix, and check the owner.
umask 002
wp plugin update --all
Confirm Updates Work Again
Retry the update from Dashboard → Updates; it should complete without the warning. From a shell, run the update as the PHP user:
sudo -u www-data wp plugin update plugin-name
Success: Updated 1 of 1 plugins.
Then reload Tools → Site Health: the Plugin temporary backup directory exists but is not writable item is gone once PHP can write to the folder, and your updates have their rollback safety net back.
Comments