Half of all "my site is broken" tickets that reach us are permissions. A plugin cannot write to uploads, a deploy script created files as root, or someone ran chmod -R 777 and now the server flags everything as a risk. Ten minutes with this guide and you will never need to guess again.
Reading an ls -l line
ls -l /var/www/vhosts/example.com/httpdocs/
# -rw-r--r-- 1 example psacln 418 Sep 12 10:02 index.php
# drwxr-xr-x 5 example psacln 4096 Sep 12 10:02 wp-contentTake the first field apart:
| Part | Meaning |
|---|---|
- or d |
regular file, or directory |
rw- |
what the owner (example) can do: read, write, not execute |
r-- |
what the group (psacln) can do: read only |
r-- |
what everyone else can do: read only |
Then example psacln is the owner and group. Every permission question is one of those three columns.
What the numbers mean
Each column is a number: read = 4, write = 2, execute = 1. Add them up.
| Number | Permissions | Typical use |
|---|---|---|
7 |
rwx | owner of a directory |
6 |
rw- | owner of a file |
5 |
r-x | everyone else, on a directory |
4 |
r-- | everyone else, on a file |
0 |
--- | nothing |
So 644 is owner read/write, everyone else read — the right default for files. 755 adds execute — the right default for directories (on a directory, "execute" means "may enter it"). 600/700 mean "only the owner", which is what wp-config.php and .env should be.
chmod: set permissions
chmod 644 index.php # one file
chmod 755 wp-content # one directory
chmod 600 wp-config.php # secrets: owner onlyTo fix an entire site in one go without giving files execute:
cd /var/www/vhosts/example.com/httpdocs
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
chmod 600 wp-config.phpThe symbolic form is handy for one change at a time — u owner, g group, o others, a all:
chmod u+x deploy.sh # let the owner run the script
chmod go-w config/ # remove write from group and otherschown: set the owner
Permissions are only half of it. If the web server runs as a different user than the one who owns the files, 644 still means "no write". On Plesk, PHP runs as the subscription's system user and the group is psacln:
chown -R example:psacln /var/www/vhosts/example.com/httpdocsOn a plain Ubuntu box with Nginx and PHP-FPM, the user is usually www-data:
chown -R www-data:www-data /var/www/example.comFind out which user PHP actually runs as before you change anything:
ps aux | grep -E 'php-fpm|httpd|apache2' | headWhy chmod 777 is never the fix
777 lets every account on the machine write to the file. On shared hosting, that is every other customer. On a VPS, it is any process that gets compromised — a vulnerable plugin can then rewrite your .htaccess, drop a web shell, and spread. Plesk and most malware scanners flag 777 for a reason. If something needs write access, give it to the right owner, not to the world.
Quick fixes for common errors
"Permission denied" when uploading in WordPress — the uploads directory is not owned by the PHP user:
chown -R example:psacln wp-content/uploads
chmod 755 wp-content/uploads"Failed to open stream: Permission denied" for a config file — the file is 600 and owned by someone else. Fix the owner, not the mode.
A script that "cannot be executed" — missing the x bit: chmod u+x script.sh.
Files created by root after a deploy — you ran git pull or composer install as root. Re-own the tree, and next time run deploys as the site user or with sudo -u example.
Directories deserve a second look
Two bits on directories confuse people:
- Sticky bit (
chmod +t /tmp) — anyone can create files, only the owner can delete their own. That is why/tmpshows asdrwxrwxrwt. - setgid (
chmod g+s dir) — new files inherit the directory's group. Useful on shared project folders so everything stays inpsaclnwithout re-runningchown.
On VPSPioneer shared and reseller plans, ownership is set correctly at account creation and the File Manager shows the mode next to every file. On a managed VPS we set it up per site and put it right when a deploy breaks it — just open a ticket.