Installation Failed: Could Not Create Directory
WordPress tried to write a folder and the server said no. The message does not say which folder or why, and the three usual reasons — ownership, a full disk, a missing upgrade directory — each need a different fix.
The server refused to create a folder, and the message hides which folder. The plugin and theme screens show it as "Installation failed: Could not create directory." in the install card; the upload form prints "Could not create directory." with the path after it, and WP-CLI reports the same sentence. All of them are the upgrader reporting a failed mkdir during a plugin, theme or core install. The failing path is one of a small set, the cause is one of a smaller set, and guessing at chmod 777 is the one response that makes the next problem worse.
Find the directory first
The path is not in the debug log — the failed mkdir is silenced — but it is in the installer's own output. Install from the upload form on Plugins › Add Plugin › Upload Plugin rather than with the Install Now button in the plugin directory: the page-based installer prints the message with the full path after it, "Could not create directory. /var/www/site/wp-content/plugins/slug/", while the card shows only the bare sentence. The candidates:
| Path | When it is created |
|---|---|
wp-content/upgrade/ |
Every install and update: the zip is unpacked here first |
wp-content/plugins/<slug>/ or wp-content/themes/<slug>/ |
The final move |
| A folder inside the unpacked zip | A zip whose entries the extractor cannot create under upgrade/ |
Two neighbouring failures print different messages and are not this one: the rollback backup folder has its own wording, "Could not create the upgrade-temp-backup directory", and a media upload that cannot create its month folder says "Unable to create directory … Is its parent directory writable". If you see those, the cause is still ownership or disk, but the folder is a different one. A package that never arrived at all fails a step earlier, with Download failed. For anything the installer does not say, the three-constant debug mode setup catches PHP warnings from the same request.
Cause 1: ownership, not permissions
WordPress writes as the user PHP runs under — www-data, apache, nginx, or the account name on shared hosting. If wp-content is owned by a different user with 755, that user can write and PHP cannot. The common path to this state is a deploy, migration or manual upload done as root or as an SFTP user, leaving files the web server does not own.
ls -ld wp-content wp-content/plugins wp-content/upgrade
ps -o user,comm -C php-fpm,php-fpm8.3,apache2,httpd | sort -u
The first command shows the owner; the second lists the users PHP processes run as — the master process is root, the workers are the user that matters. When they differ, change the owner, not the mode:
chown -R www-data:www-data wp-content
find wp-content -type d -exec chmod 755 {} \;
find wp-content -type f -exec chmod 644 {} \;
chmod 777 makes the folder writable by every account on the server, which on shared hosting means every other customer. It does solve the error. It also creates the condition behind most hacked sites on that kind of host.
Cause 2: the FS_METHOD trap
When PHP cannot write, WordPress normally asks for FTP credentials rather than failing. A site that shows this error instead of the FTP prompt has often been told define( 'FS_METHOD', 'direct' ) in wp-config.php — which suppresses the prompt and makes WordPress write as the PHP user, which then fails. The constant is a way to hide a prompt, not a way to grant access; the full reasoning is in FS_METHOD. Remove the constant and fix ownership, or keep it after ownership is fixed.
Cause 3: disk, quota or inodes
A mkdir also fails when there is no room. Hosting quotas count both bytes and file count:
df -h .
df -i .
A full disk is obvious; an inode limit is not — the disk shows free space and the file count is maxed, often by cache plugins or a log that grew for a year. Clear the cache directory and rotate logs, then retry. Shared hosting panels report the same numbers under disk usage.
Cause 4: a leftover folder
An install that failed halfway leaves a partial folder in wp-content/plugins/<slug> or in upgrade/. The next attempt may report this error if the leftover has the wrong owner, or the destination folder already exists if it merely exists. Delete the partial folder over SFTP or SSH and install again.
Cause 5: open_basedir and hosting restrictions
Some hosts restrict PHP to specific directories with open_basedir. If wp-content/upgrade resolves to a path outside the allowed list — a symlinked wp-content is the classic case — the write is refused even with correct ownership, and because the mkdir is silenced nothing is logged. A one-line test file calling mkdir() on the same path without suppression prints the restriction. The fix is in the PHP configuration or with the host, not in WordPress.
Fixes by hosting setup
The causes are the same everywhere; where you fix them differs:
- Shared hosting with cPanel. PHP normally runs as your own account, so ownership is rarely wrong unless files were restored by the host or copied in by another user. Check the disk and inode figures on the panel's home screen first; a full quota is the most common cause on this kind of account.
- Plesk. Files belong to the subscription's system user. Folders uploaded over FTP with a different account, or restored as root, are the usual mismatch; Plesk's own repair tools for a subscription can reset ownership, and the host can do it if you cannot find them.
- A VPS on Ubuntu or Debian. The commands in cause 1 apply as written; PHP-FPM pools can run as a user other than
www-data, so check the pool'suser =line in its configuration before changing anything. - Docker. A bind-mounted
wp-contentkeeps the owner it has on the host, while the official WordPress image runs PHP aswww-data, user ID 33 (82 on Alpine tags). Change the host folder's owner to that ID, or run the container as your own user, so both sides agree:
sudo chown -R 33:33 ./wp-content
- Local development tools. Desktop stacks that run the web server as a system account hit the same ownership problem on files created by your own user. Tools that run it as your user rarely do.
- Managed WordPress hosts. Some mount the code read-only or block installs outside their dashboard;
DISALLOW_FILE_MODSinwp-config.phpremoves the install buttons entirely. If installs are meant to work and do not, it is a support ticket, not a permissions change.
Verify
Retry the install from the upload form. If it succeeds, open the plugin folder and confirm its owner matches the PHP user, so the next update does not fail. If it fails again, the message now carries a path you have not checked — compare its owner and free space with the steps above. If the wording has changed to name upgrade-temp-backup or an uploads folder, you have moved on to a different folder with the same two causes.
Frequently asked
- Usually wp-content/upgrade, where the zip is unpacked, or wp-content/plugins/<slug> and wp-content/themes/<slug>, the final destination. The path is printed after the message when you install from the upload form rather than the Install Now button; it is not written to the debug log, because the failed mkdir is silenced.
- Find the folder from the upload form's output, then compare its owner with the user PHP runs as. Change the owner to that user rather than setting 777, free up disk space or inodes if the account is full, and delete any half-installed plugin folder before trying again.
- Only if the prompt was for FTP credentials and the web server can actually write the folder. If the folder is owned by another user, direct makes WordPress attempt the write itself and fail with the same message. Fix ownership first.