Every file and directory on a Unix-style system has an owner, a group, and a set of permissions saying what the owner, the group, and everyone else is allowed to do with it. Get this wrong and "permission denied" follows you everywhere; get it right and it just works.
Reading a permissions line
Run ls -l in any directory and look at the leftmost column:
-rw-r--r-- 1 alice staff 1234 May 14 09:00 notes.txt
drwxr-xr-x 3 alice staff 102 May 14 09:00 photos
Decode the first ten characters:
-rwxr-xr--
│└┬┘└┬┘└┬┘
│ │ │ └── permissions for everyone else (read only here)
│ │ └───── permissions for the group (read + execute)
│ └──────── permissions for the owner (read + write + execute)
└────────── file type: - regular file, d directory, l symlink
Each three-letter group is read/write/execute (r/w/x) for that audience. A dash means "no, can't."
What execute means on a directory
For a file, x means "this is a program you can run." For a directory, x means "you're allowed to enter (cd into) this directory." You can have a directory you can read (r, list files) but not enter (no x), or one you can enter but not list. The two combine in odd ways — knowing this saves a lot of head-scratching.
Owner and group
The other two columns are who owns the file and which group it belongs to. The owner is one person; the group is potentially many.
Change owner
sudo chown bob notes.txt # bob now owns it
sudo chown bob:developers notes.txt # bob owns it, group is developers
sudo chown -R bob:developers project/ # recursively, every file inside
Change just the group
sudo chgrp developers notes.txt
chmod: changing permissions
Two notations — pick whichever you prefer.
Symbolic ("words")
chmod u+x script.sh # add execute for user (owner)
chmod g+w notes.txt # add write for group
chmod o-r secret.txt # remove read for others
chmod a+r everyone.txt # add read for all (user, group, other)
chmod u=rw,g=r,o= notes.txt # set exactly: owner rw, group r, other nothing
Who: u user (owner), g group, o other, a all. Verb: + add, - remove, = set exactly.
Numeric (octal)
Each three-letter cluster is a number from 0 to 7. Compute it by adding: read = 4, write = 2, execute = 1.
chmod 644 notes.txt # rw- r-- r-- (the standard file)
chmod 755 script.sh # rwx r-x r-x (the standard executable)
chmod 600 ~/.ssh/id_ed25519 # rw- --- --- (your private key, locked down)
chmod 700 ~/.ssh # rwx --- --- (your ssh directory)
chmod 750 project/ # rwx r-x --- (owner + group, no one else)
Memorise the three: 644 for normal files, 755 for executables and directories, 600/700 for private things. Most chmods are one of those.
The sticky bit (and friends)
Three more permission bits exist beyond r/w/x. You meet them rarely, but when you do, they're mysterious.
Sticky bit on a directory: chmod +t
On a directory, the sticky bit means "even though anyone can write here, you can only delete your own files." That's how /tmp works — everyone can create files in it, but Alice can't delete Bob's.
ls -ld /tmp
# drwxrwxrwt 18 root root 4096 May 14 09:00 /tmp
# ^ that t is the sticky bit
setuid and setgid: chmod u+s / g+s
setuid on an executable makes it run as its owner instead of as the user invoking it. That's how passwd can write to /etc/shadow when run by a normal user.
ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root ...
# ^ the s in place of x means setuid
You almost never set this yourself — it's a security minefield. But you'll see it on system binaries.
setgid on a directory makes new files inside inherit the directory's group. Useful for shared project directories.
umask: what new files get by default
umask is the "default permissions" knob, expressed as the bits to subtract from full permissions. Most distros default to 022:
- New files get
666 - 022 = 644(rw-r--r--). - New directories get
777 - 022 = 755(rwxr-xr-x).
To make your new files private by default:
umask 077 # files get 600, dirs get 700
Put that in your ~/.bashrc or ~/.zshrc.
ACLs: when the three-tier model isn't enough
If "owner + one group + other" isn't expressive enough — say you want Alice and Bob to both have write, but not the rest of the group — you reach for Access Control Lists:
setfacl -m u:alice:rw notes.txt
setfacl -m u:bob:rw notes.txt
getfacl notes.txt # show the full ACL
Files with ACLs show a + at the end of the permission column in ls -l. Most filesystems support them; you almost never need them — but when you do, they're what you're looking for.
Two routines that fix 90% of "permission denied"
# I copied files in as root by mistake — give them back to me
sudo chown -R $USER:$USER ~/folder/
# scripts don't run — they need execute
chmod +x script.sh