Wrong file permissions cause two kinds of WordPress problems: too strict, and you get “Could not create directory” errors or FTP prompts during updates; too loose (the infamous 777), and any compromised plugin or other site can modify your files. Here’s how to set them correctly on a Linux VPS.
Background: Linux file permissions explained.
The standard setup
On a typical Nginx or Apache server, PHP-FPM runs as www-data (Debian/Ubuntu) or nginx/apache (RHEL family).
| Path | Owner:group | Permission |
|---|---|---|
| Directories | www-data:www-data (or youruser:www-data) |
755 (or 750) |
| Files | same | 644 (or 640) |
wp-config.php |
same | 640 or 600 |
.htaccess (Apache) |
same | 644 |
Apply it:
cd /var/www/example.com
sudo chown -R www-data:www-data .
sudo find . -type d -exec chmod 755 {} \;
sudo find . -type f -exec chmod 644 {} \;
sudo chmod 640 wp-config.php
With this setup, WordPress can update itself, install plugins and upload media directly, without asking for FTP details.
Never use 777
777 means any user and any process on the server can write the files. On a VPS with several sites or users, one compromised site can then infect the others. If a guide or plugin tells you to use 777, fix the ownership instead: the web server user needs to own the files (or be in a group with write access). 777 is never needed.
“Could not create directory” or FTP credential prompts
WordPress checks whether it can write files as the PHP user. If not, it asks for FTP details or fails to update. Fix it:
ps aux | grep php-fpm | grep -v root | head -2 # which user runs PHP?
sudo chown -R www-data:www-data /var/www/example.com
If you deliberately keep files owned by another user, you can add to wp-config.php:
define( 'FS_METHOD', 'direct' );
This only works if PHP can actually write the files.
A hardened alternative: separate owner and PHP user
For stricter security, the files are owned by a deploy user, and PHP gets write access only where it needs it:
sudo chown -R deploy:www-data /var/www/example.com
sudo find /var/www/example.com -type d -exec chmod 750 {} \;
sudo find /var/www/example.com -type f -exec chmod 640 {} \;
# writable only for uploads (and cache dirs if your plugins need them)
sudo chown -R www-data:www-data /var/www/example.com/wp-content/uploads
Then PHP (and malware running through it) can’t modify core, theme or plugin files. The trade-off: dashboard updates and plugin installs no longer work. You update with WP-CLI as the deploy user, or through Git deployments:
sudo -u deploy wp core update && sudo -u deploy wp plugin update --all
See WordPress Git deployment and WP-CLI guide.
One site, one PHP-FPM pool
If you host several sites, give each its own Linux user and PHP-FPM pool, so a hack on one site can’t touch the others:
; /etc/php/8.3/fpm/pool.d/example.conf
[example]
user = example
group = example
listen = /run/php/php8.3-fpm-example.sock
listen.owner = www-data
listen.group = www-data
Point that site’s Nginx fastcgi_pass at its own socket. See PHP-FPM tuning.
Protect sensitive files in the web server
Permissions control who on the server can read files. The web server config controls what visitors can fetch. Block access to wp-config.php, hidden files and PHP in uploads. See the ideal Nginx config for WordPress.
Check your permissions
find /var/www/example.com -perm -o+w -ls # anything world-writable? should be empty
stat -c '%a %U:%G %n' /var/www/example.com/wp-config.php
Quick reference
| Item | Setting |
|---|---|
| Directories | 755 (or 750) |
| Files | 644 (or 640) |
| wp-config.php | 640 / 600 |
| Owner | PHP user (e.g. www-data), or a deploy user + writable uploads |
| Never | 777 |
Related: WordPress hardening and WordPress malware removal.