Skip to content
ThemesCraft.

How to Fix Plugins Not Installing on WordPress: 14 Causes and Fixes

Fix plugins not installing on WordPress by matching the exact error message to its cause. Fourteen causes across permissions, PHP limits, firewalls and disabled installers.

Quick answer

Plugins fail to install on WordPress for one of four reasons: the web server cannot write to wp-content/plugins, PHP runs out of memory or upload headroom mid-install, your host or a security rule blocks the request, or the installer is disabled in configuration. Read the exact error string WordPress shows you first. It names the category almost every time, and the wrong fix applied to the right error wastes an afternoon.

Almost every guide to this problem opens with the same five suspects: file permissions, memory limit, plugin conflict, user role, debug mode. They are all real causes. They are also the five that are easiest to write about, which is not the same thing as the five that are most likely to be your problem.

The thing those guides skip is that WordPress tells you which category you are in. It prints a specific string. Installation failed: Could not create directory is a different failure from The link you followed has expired, which is different again from a blank white page after you click Install Now. Treating them as interchangeable is why people end up chmod-ing their entire install to 777 to fix a problem that was a 2 MB upload cap.

This guide is organised the way the problem actually presents: error message first, cause second, fix third. Fourteen causes, grouped into the four categories above, plus the diagnostic order that gets you to the right one fastest. ThemesCraft has no affiliation with any host named here.

Start here: match your error message to a cause

Before you change anything, copy the exact text WordPress showed you. This table maps the strings you are most likely to see to the section of this guide that fixes them.

What you seeWhat it almost always meansGo to
Installation failed: Could not create directoryThe PHP user cannot write into wp-content/pluginsPermissions and ownership
Installation failed: Destination folder already existsA previous failed install left a partial folder behindLeftover folders
The uploaded file exceeds the upload_max_filesize directivePHP upload cap is smaller than the plugin ZIPUpload and POST limits
The link you followed has expiredpost_max_size exceeded, so the nonce never arrivedUpload and POST limits
Allowed memory size of X bytes exhaustedPHP memory limit too low for the unzip stepPHP memory limit
Blank white screen after clicking InstallFatal error with display off. Check the logReading the actual error
An unexpected error occurred / Could not connect to WordPress.orgOutbound HTTP blocked, or the API is unreachableOutbound connections
403 Forbidden, or the page reloads with nothingA WAF or mod_security rule ate the requestFirewall and mod_security
No Add New button in the Plugins menu at allDISALLOW_FILE_MODS is set, or your role lacks the capabilityInstaller disabled and user roles
WordPress asks for FTP credentialsOwnership mismatch, so WordPress falls back to FTPThe FTP credentials prompt
Error strings as they appear in WordPress 6.x. Wording varies slightly by version; match on the distinctive phrase rather than the whole sentence.

Category one: the server cannot write the files

This is the largest category and the one where bad advice does the most damage. WordPress installs a plugin by downloading a ZIP to a temporary directory, unpacking it, and writing the result into wp-content/plugins. Any link in that chain that is not writable by the PHP process stops the install.

1. Directory and file permissions

The correct values are 755 for directories and 644 for files. Not 777. Setting 777 makes the install work by making the directory world-writable, which on shared hosting means writable by processes that are not yours.

cd /path/to/wordpress
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
chmod 600 wp-config.php

2. Ownership does not match the PHP user

Permissions are only half of it. 755 means the owner can write; it does not help if the owner is root and PHP runs as www-data. This is the single most common cause on a self-managed VPS, and it usually appears right after someone unpacks WordPress over SSH as root.

# Find out who PHP actually is first
ps aux | grep -E 'php-fpm|apache2|nginx' | head

# Then match ownership to it (www-data is common on Debian/Ubuntu)
chown -R www-data:www-data /path/to/wordpress/wp-content

3. The FTP credentials prompt

If WordPress asks for FTP details instead of just installing, it has tested whether it can write the file itself, decided it cannot, and fallen back to its FTP transport. The prompt is a symptom of cause 2, not a separate problem. Fix the ownership and the prompt disappears.

Watch out

The workaround you will find everywhere is to add define('FS_METHOD', 'direct'); to wp-config.php. It does suppress the prompt, but only because it forces WordPress to stop checking. If ownership is genuinely wrong, the install now fails with a less helpful error instead. Use it only after you have confirmed the PHP user owns wp-content.

4. Leftover folders from a failed install

Destination folder already exists means a previous attempt got far enough to create the directory and then died. WordPress will not overwrite it. Delete the partial folder under wp-content/plugins/ and retry. While you are there, check for a stray .maintenance file in the WordPress root, which is what leaves a site stuck on Briefly unavailable for scheduled maintenance.

5. The disk is full

Rarely mentioned, surprisingly common, and it produces confusing errors because the unzip step fails halfway. Check before you spend an hour on permissions. On shared hosting the quota shown in your control panel is the one that matters, and it usually includes email.

df -h                    # disk space
df -i                    # inodes - a full inode table fails the same way
du -sh wp-content/*      # find what is using it

Category two: PHP runs out of room

6. PHP memory limit

Unzipping a plugin holds its contents in memory. A 128 MB limit is fine for most, and not fine for the large commercial page builders and their template libraries. WordPress ships a separate constant for admin-side operations, which is the one that governs installs.

// wp-config.php, above the "stop editing" line
define('WP_MEMORY_LIMIT', '256M');
define('WP_MAX_MEMORY_LIMIT', '512M');

That constant cannot exceed what PHP itself allows. If your host caps memory_limit at 128 MB, raising the WordPress constant does nothing. Check the real value under Tools, then Site Health, then Info, then Server, rather than trusting what you set.

7. upload_max_filesize is smaller than the ZIP

Only affects manual uploads via Add New, then Upload Plugin. Many hosts still ship a 2 MB default. Plenty of legitimate plugins are larger than that.

8. post_max_size is the one that causes the weird error

The link you followed has expired is the most misleading message WordPress produces. Nothing has expired. post_max_size was exceeded, PHP discarded the entire POST body before WordPress saw it, so the security nonce that was in that body never arrived, and WordPress reported a missing nonce the only way it knows how.

post_max_size must be larger than upload_max_filesize, because it contains the file plus the rest of the form.

; php.ini - post_max_size must exceed upload_max_filesize
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
max_execution_time = 300

9. max_execution_time on a slow download

A 30-second limit against a large plugin pulled from a slow mirror times out mid-download. The install appears to hang and then fails. 300 seconds is a sane admin-side value.

Pro tip

Site Health at Tools, then Site Health, then Info shows you the values PHP is actually running with, not the ones you wrote in a file that may not be loaded. Check there after every change. Many hosts ignore a root-level php.ini entirely and read a per-account file instead.

Category three: something is blocking the request

10. mod_security or a web application firewall

This is the cause that almost no tutorial covers, and on shared hosting it is a top-three culprit. A mod_security rule sees a large POST containing PHP files and treats it as an upload attack. The signature is distinctive: a 403, or a page that simply reloads with no message at all, with nothing in the WordPress debug log because WordPress was never reached.

You usually cannot fix this yourself. Ask your host to check the mod_security audit log for your IP at the timestamp of the attempt, and to whitelist the rule ID for your account. Give them the timestamp; without it they will tell you nothing is wrong.

11. Outbound connections to WordPress.org are blocked

Installing from the repository requires your server to make an outbound HTTPS request to api.wordpress.org and downloads.wordpress.org. On a locked-down corporate network or a hardened VPS, outbound 443 from the web user may simply not be allowed. Symptom: search in Add New returns nothing, or an unexpected error.

curl -I https://api.wordpress.org/plugins/info/1.2/
curl -I https://downloads.wordpress.org/plugin/classic-editor.zip

Also check that WP_HTTP_BLOCK_EXTERNAL is not defined in wp-config.php. It is a legitimate hardening constant that blocks exactly this, and it is frequently inherited from a boilerplate config someone copied years ago.

12. A security plugin is blocking the installer

Wordfence, Solid Security and similar tools all ship options to prevent file modification from the dashboard. When enabled, they are doing their job. Check the plugin’s own settings before you touch the server. This overlaps with the plugin-conflict advice you have read elsewhere, but the mechanism is specific and worth knowing.

Category four: the installer is switched off

13. DISALLOW_FILE_MODS

If the Add New button is missing entirely rather than failing when clicked, this is almost certainly why. Managed hosts set it deliberately, and so do agencies that deploy via Git. Removing it on a managed host may break their deployment model, so ask before you delete the line.

// Look for either of these in wp-config.php
define('DISALLOW_FILE_MODS', true);   // hides Add New completely
define('DISALLOW_FILE_EDIT', true);   // only hides the code editors - harmless

14. Your user role lacks the capability

Only Administrator can install plugins, and on Multisite only Super Admin can, because the capability is network-scoped. Editors, Authors and Contributors will never see the option. If you are certain you are an administrator, a membership or role-editor plugin may have modified the install_plugins capability.

Reading the actual error instead of guessing

If you have a white screen and no message, turn logging on and reproduce the failure. Log to a file rather than to the screen, so you are not printing errors to visitors while you debug.

// wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);      // writes to wp-content/debug.log
define('WP_DEBUG_DISPLAY', false); // keep it off the screen
@ini_set('display_errors', 0);

Then retry the install and read the last lines of wp-content/debug.log. If that file is empty after a failed attempt, the request never reached PHP, which points you straight at category three.

The two-command bypass

If you have SSH, WP-CLI sidesteps the browser, the nonce, the POST limits and the WAF in one move. If this works and the dashboard does not, you have proved the problem is in the HTTP layer rather than the filesystem, which is a genuinely useful result.

wp plugin install classic-editor --activate
wp plugin install ./my-plugin.zip     # from a local file
wp plugin list --status=active

The manual upload, done properly

When nothing else works, install by hand over SFTP. Unzip locally, upload the resulting folder to wp-content/plugins/, then activate from the dashboard. Two details people get wrong: upload the folder, not the ZIP, and make sure you do not end up with a doubled directory such as plugins/my-plugin/my-plugin/, which WordPress will not detect. The plugin’s main PHP file with its header comment must sit one level inside the plugin folder.

After uploading, set ownership to the PHP user or you will hit cause 2 the next time the plugin tries to update itself.

The order to work through

  1. Read the error string and use the table at the top. This resolves it outright perhaps half the time.
  2. Check Site Health. Memory, PHP version, and whether loopback requests and the REST API are working. Two minutes, no risk.
  3. Try a different plugin. Install something tiny like Classic Editor. If that succeeds, your problem is size-related, not permission-related, and you can skip the entire first category.
  4. Turn on debug logging and reproduce. An empty log means a firewall; a fatal error means memory or a conflict.
  5. Deactivate security plugins one at a time, then switch to a default theme. This is the classic conflict test, and it belongs here rather than at step one.
  6. Contact the host with the timestamp of a failed attempt and ask specifically about mod_security. Not “my plugins won’t install”, which gets you a link to a generic article.

If you are hitting these limits repeatedly, the underlying issue is usually the hosting tier rather than any individual setting. A host that caps PHP memory at 128 MB and upload size at 2 MB in 2026 is telling you something about the resources behind the plan. Our comparison of WordPress hosting providers covers which tiers ship sensible defaults, and if a botched update is what got you here, the recovery steps are in our guide to fixing a site after a plugin update breaks it.

Frequently asked questions

Why does WordPress say installation failed could not create directory?

The PHP process cannot write into wp-content/plugins. Nine times out of ten the cause is ownership rather than permission bits: the files belong to root or to your SSH user, while PHP runs as www-data. Set directories to 755 and files to 644, then chown wp-content to whichever user PHP actually runs as. Do not use 777, which makes the directory writable by every process on a shared server.

It means post_max_size was exceeded. PHP discarded the whole POST body before WordPress could read it, so the security nonce never arrived, and a missing nonce is reported as an expired link. Nothing has expired. Raise post_max_size above upload_max_filesize in php.ini and the message goes away.

Should I set my WordPress folders to 777 to fix this?

No. 777 makes a directory writable by any process on the server, including other accounts on shared hosting. It fixes the symptom by removing the protection. The correct values are 755 for directories and 644 for files, with ownership matched to the PHP user. If 777 is the only thing that works, ownership is wrong and that is what needs fixing.

Why is there no Add New button in my Plugins menu?

Either DISALLOW_FILE_MODS is defined as true in wp-config.php, or your user role does not hold the install_plugins capability. Managed hosts and Git-based deployment setups set that constant deliberately, so check with your host before removing it. On Multisite, only a Super Admin can install plugins at all.

My debug log is empty but the install still fails. What now?

An empty log after a failed attempt means the request never reached PHP, which points at the web server layer rather than WordPress. The usual culprit is a mod_security rule or a WAF treating a large POST full of PHP files as an attack. Note the exact timestamp of a failed attempt and ask your host to check the mod_security audit log for your IP at that moment.

Is it safe to install a plugin manually over SFTP?

Yes, and it is the reliable fallback when the dashboard installer will not cooperate. Unzip locally, upload the plugin folder rather than the ZIP into wp-content/plugins, then activate from the dashboard. Watch for a doubled folder such as plugins/name/name, which WordPress will not detect, and set ownership to the PHP user afterwards so automatic updates keep working.

Does raising WP_MEMORY_LIMIT always increase available memory?

No. That constant cannot exceed the memory_limit PHP itself enforces. If your host caps PHP at 128MB, defining 512MB in wp-config.php changes nothing. Check the value PHP is actually using under Tools, then Site Health, then Info, then Server, rather than trusting what you wrote in the file.

Can a security plugin stop me installing other plugins?

Yes. Wordfence, Solid Security and several others include an option to prevent file modification from the dashboard, and when it is switched on it blocks installs by design. Check the security plugin settings before you start changing server configuration, because nothing on the server is wrong in that case.

Leave a response

Your email address will not be published. Required fields are marked *