Linux File Permissions Explained
Every file and directory on Linux has permissions that decide who can read, write, or execute it. The model is simple once you see it — but until you do, “permission denied” feels random. Learn this and you stop fighting your own system.
Read the permissions of any file
ls -l myfile.sh
# -rwxr-xr-- 1 alice devs 1234 Apr 26 10:00 myfile.sh
That string at the start tells you everything:
- rwx r-x r--
type owner group others
- type:
-file,ddirectory,lsymlink,ccharacter device,bblock device. - owner (alice): can read, write, execute.
- group (devs): can read, execute. Cannot write.
- others: can read only.
Three permissions, three audiences
| Permission | On a file | On a directory |
|---|---|---|
r (4) |
Read contents | List filenames |
w (2) |
Modify contents | Create/delete files inside |
x (1) |
Execute as program | Enter (cd into) the directory |
chmod: change permissions
Octal (numeric) form
Add up the numbers: r=4, w=2, x=1. Three digits, one per audience (owner, group, others).
chmod 755 script.sh # rwxr-xr-x (owner all, group/others read+exec)
chmod 644 file.txt # rw-r--r-- (owner read/write, others read)
chmod 600 secrets # rw------- (only owner can read/write)
chmod 700 ~/.ssh # rwx------ (only owner can enter / list)
Common patterns to memorize
- 755 — executables and directories most users should access.
- 644 — most regular files.
- 600 — sensitive files (SSH keys, .env files).
- 700 — sensitive directories (~/.ssh).
Symbolic form
Add (+), remove (-), or set (=) permissions for user (u), group (g), other (o), or all (a):
chmod +x script.sh # add execute for everyone
chmod u+x script.sh # add execute for owner only
chmod o-r secrets.txt # remove read for others
chmod g+w shared.txt # add write for group
chmod a-w readonly.txt # remove write for everyone
chown: change ownership
sudo chown alice file.txt # change owner
sudo chown alice:devs file.txt # change owner AND group
sudo chown :devs file.txt # change group only
sudo chown -R alice:devs /var/app # recursive on a directory tree
Special bits: setuid, setgid, sticky
setuid (4xxx) — run as owner
An executable with setuid runs as its owner, not as you. passwd uses this so you can change your own password (which writes to /etc/shadow, owned by root).
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root ... ← the 's' replaces 'x' for owner
chmod u+s file
chmod 4755 file
setgid (2xxx) — run as group, or inherit group on directories
On a directory: new files created inside inherit the group of the directory. Useful for shared team folders.
chmod 2775 /shared
ls -ld /shared
# drwxrwsr-x ... ← 's' for group
sticky (1xxx) — only owner can delete
On a directory: anyone can write files, but only the file’s owner can delete their own files. Used on /tmp.
ls -ld /tmp
# drwxrwxrwt ... ← 't' at the end
Default permissions: umask
When you create a file, it gets default permissions (typically 644 for files, 755 for directories). The default is controlled by umask:
umask # show current (typically 022)
umask 077 # only owner can read new files
Common mistakes
chmod -R 777 / (DANGEROUS)
Never do this. It makes everything world-writable, opens the door to attackers, and breaks SSH (which refuses to use world-readable keys).
SSH key has wrong permissions
If ~/.ssh/id_rsa is readable by anyone, SSH refuses to use it. Fix:
chmod 600 ~/.ssh/id_rsa
chmod 700 ~/.ssh
Script “won’t run”
./script.sh
# bash: ./script.sh: Permission denied
chmod +x script.sh # fix it
./script.sh
What to learn next
Now that you control file access, the next topic is bundling and moving files around — archives, compression, and the cp/rsync family.