Changing Permissions & Ownership
Every file on a Linux server has two things that control who can touch it: its permissions (what actions are allowed) and its ownership (which user and group those permissions apply to). When you deploy a website, run a database, or copy files around as root, you will eventually hit a “Permission denied” error. Fixing it correctly means knowing two commands: chmod (change mode, i.e. permissions) and chown (change owner). This page shows both, including the safe way to fix a web file that ended up owned by root, and why chmod 777 is almost always the wrong fix.
If you have not yet read how Linux permissions are structured (the rwx bits and the owner/group/other model), read File permissions first — this page assumes you understand that layout.
A quick refresher on the permission model
Every file has three sets of permissions, for three classes of people:
- u — the user who owns the file.
- g — the group that owns the file.
- o — other (everyone else on the system).
Each set can have r (read), w (write), and x (execute). Running ls -l shows them:
ls -l index.html
Output:
-rw-r--r-- 1 deploy www-data 1240 Jun 15 09:14 index.html
Reading that line: deploy is the owning user, www-data is the owning group, the user can read and write (rw-), the group can read (r--), and other can read (r--).
Changing permissions with chmod
chmod (“change mode”) sets the rwx bits. It accepts two styles: symbolic (easy to read, good for small tweaks) and octal (numeric, good for setting everything at once).
Symbolic mode (u/g/o + r/w/x)
Symbolic mode reads like a sentence: who + what change + which permission. Use + to add, - to remove, and = to set exactly.
# Make a script runnable by its owner
chmod u+x deploy.sh
# Let the group read and write a shared config
chmod g+rw shared.conf
# Remove all access for "other" (everyone else)
chmod o-rwx secrets.env
# Add execute for user, group, and other at once
chmod a+x backup.sh
a means “all” (u, g, and o together). Symbolic mode is best when you want to change one bit without disturbing the others — for example, just adding execute to a script.
Octal mode (numbers like 755)
Octal mode sets all three classes in one number. Each digit is the sum of: read = 4, write = 2, execute = 1.
| Octal | Symbolic | Meaning |
|---|---|---|
| 7 | rwx | read + write + execute |
| 6 | rw- | read + write |
| 5 | r-x | read + execute |
| 4 | r— | read only |
| 0 | --- | no access |
The three digits map to user, group, other in that order:
# 755: owner can do everything; group and other can read + run
chmod 755 /usr/local/bin/myscript
# 644: owner reads/writes; everyone else reads only (typical for web files)
chmod 644 index.html
# 600: owner reads/writes; nobody else sees it (good for secrets)
chmod 600 ~/.ssh/id_ed25519
# 700: a private directory only the owner can enter
chmod 700 ~/.ssh
Directories need the execute bit to be entered.
chmod 644on a folder makes it impossible tocdinto, even for the owner. Use755for directories and644for plain files.
To apply a change to a whole directory tree, add -R (recursive). Be careful — recursion applies the same bits to files and directories, which is usually wrong because directories need execute. Use find to separate them:
# Files get 644, directories get 755 — the correct way to fix a web tree
sudo find /var/www/mysite -type f -exec chmod 644 {} \;
sudo find /var/www/mysite -type d -exec chmod 755 {} \;
Changing ownership with chown and chgrp
chown changes who owns a file. The syntax is chown user:group file. You almost always need sudo, because changing ownership is a privileged action.
# Change both the owner and the group
sudo chown deploy:www-data index.html
# Change only the owner (leave the group as-is)
sudo chown deploy index.html
# Change only the group (note the leading colon)
sudo chown :www-data index.html
chgrp is a shortcut that changes only the group:
sudo chgrp www-data index.html
Like chmod, chown takes -R to recurse through a directory:
sudo chown -R deploy:www-data /var/www/mysite
Real example: fixing a web file owned by root
This is the single most common ownership problem in real DevOps work. You log in, run sudo nano or sudo cp to drop a file into your site, and now that file is owned by root. Nginx runs as the www-data user, so when a visitor requests the page, Nginx cannot read it and returns a 403 Forbidden.
First, confirm the problem:
ls -l /var/www/mysite/config.php
Output:
-rw------- 1 root root 820 Jun 15 10:02 /var/www/mysite/config.php
Owned by root:root and readable only by root. Nginx (running as www-data) is locked out. Fix the ownership and set sane permissions:
# Give it to your deploy user and the web server's group
sudo chown deploy:www-data /var/www/mysite/config.php
# Owner reads/writes, group reads — no access for "other"
sudo chmod 640 /var/www/mysite/config.php
Output:
-rw-r----- 1 deploy www-data 820 Jun 15 10:02 /var/www/mysite/config.php
Now deploy can edit it, Nginx (in the www-data group) can read it, and random users on the box cannot. Reload Nginx if needed and the 403 is gone:
sudo systemctl reload nginx
Why 777 is almost never the right answer
When people get stuck on permissions, the internet’s worst advice is chmod 777. That sets rwxrwxrwx — every user on the system can read, write, and execute the file. It usually makes the error disappear, which is exactly why it is dangerous: it hides the real problem (wrong ownership) by removing all protection.
The real risks:
- Anyone can modify your code. If an attacker gets even a low-privilege foothold (say, through another app on the box),
777files are theirs to rewrite — they can inject a backdoor into your site. - Web servers may refuse it. PHP-FPM and SSH actively reject world-writable files and
777directories as a safety measure, so you can break the very thing you were trying to fix. - It masks the actual issue. The problem is almost always “wrong owner,” not “not enough permission.” Fix ownership with
chown, not access with777.
Security rule of thumb: grant the least access that works. A web file needs
644(or640), a directory needs755, and a secret needs600. If777seems necessary, the file is owned by the wrong user — fix that instead.
Best practices
- Fix the owner first with
chown; reach forchmodonly when ownership is already correct. - Use
644for files and755for directories in web roots; never applychmod -R 777. - Keep secrets (SSH keys,
.envfiles, credentials) at600so only the owner can read them. - When recursing, split files and directories with
find ... -type fand-type dso directories keep their execute bit. - Add the web server group (
www-data) to files Nginx must serve, instead of opening them to “other.” - Run
ls -lbefore and after a change to confirm you got the result you expected.