Three identities × three bits
Every file carries three identities — user (owner), group, others — and each has read r / write w / execute x bits. The -rw-r--r-- in ls -l is those three groups: owner can read and write, everyone else can only read.
Octal notation
| Number | Permissions | Typical use |
|---|---|---|
| 755 | rwxr-xr-x | Executables, directories others may read |
| 700 | rwx------ | Private directories and scripts |
| 644 | rw-r--r-- | Config files, static assets |
| 600 | rw------- | Private keys, files containing secrets |
| 666 / 777 | World writable | Almost always a mistake |
The digit is the sum per group: r=4, w=2, x=1, so 7 means read+write+execute and 6 means read+write.
The execute bit is special on directories
- r: can you list the entries (ls);
- w: can you create or delete entries inside;
- x: can you enter the directory and reach the files inside. Without x, r only shows names — contents stay unreadable;
- Deleting a file depends on the parent directory's w bit, not on the file's own permissions.
Useful commands
chmod 600 id_ed25519 # private key: owner only
chmod +x deploy.sh # add execute
chmod -R u+rwX,go-w /srv/app # recursive: owner rw, strip group/other write
chown -R app:app /srv/app # change owner and group
umask 022 # new files 644, new dirs 755
Note the capital X in recursive chmod: it adds execute only to directories (and files that already have it), so plain files do not all become "executable".
Five common mistakes
- Reaching for 777: it hides the real cause (wrong owner or missing directory permission) while opening the widest hole;
- Recursive chmod breaking executables: forcing 644 across a bin directory makes programs unrunnable;
- Loose private key permissions: SSH refuses to use them; they must be 600;
- Ignoring umask: different umasks produce inconsistent permissions — very common in containers;
- Forgetting root bypasses checks: verify with an unprivileged user, not root.
Real-world cases: three permission incidents
- "chmod did not fix access": a directory along the path lacks the execute bit, so you cannot traverse into it. Fix: check each level with
ls -ld; directories need at leastx. - "The service cannot read its config after deploy": wrong owner/group, or an inconsistent umask. Fix: standardise
chownandumaskinstead of masking it with 777. - "Cannot delete someone else's file": deletion depends on write permission on the parent directory (plus the sticky bit), not the file. Fix: check parent permissions and sticky-bit directories like
/tmp.
Common questions
Why can't I delete the file? Check write permission on the parent directory and any immutable attribute. Why is it still inaccessible after chmod? Every directory on the path needs the x bit. How do teams share a directory? A common group plus the setgid bit on the directory, so new files inherit its group.
A practical order for permission debugging
- Identify who is accessing: confirm the user and group the process runs as, not who you logged in as — services usually run under a dedicated account.
- Walk the whole path: reaching a file requires execute permission on every directory in the path; a missing middle level fails outright while the error names only the file.
- Separate read, write and execute: reading needs read on the file, writing needs write, and entering a directory needs execute. Assuming directories need read is a common error.
- Remember the umask: default permissions of new files depend on the umask, so "mysteriously wrong" modes usually come from configuration, not the file.
- Check extended attributes and ACLs: when base permissions allow access but it still fails, look for access control lists or security module policy overriding them.
Fix with the least privilege needed rather than opening access to everyone; broad temporary grants tend to stay in production unnoticed.