File permissions & ownership cheat sheet
Unix permissions answer one question per file: who may do what. The who is three classes — owner (u), group (g), others (o); the what is read, write, execute. Numeric modes pack the three classes into octal digits, symbolic modes adjust them in place, and everything on this sheet operates on those two representations.
The sheet moves from everyday chmod through ownership to the special bits (where the honest advice is mostly caution) and finishes with ACLs — the escape hatch for granting one extra user access without reshuffling groups. SSH-related rows matter more than they look: a loose ~/.ssh is the most common reason a key is refused.
Numeric chmod: the everyday modes
Digit arithmetic — each class gets one octal digit, summed from r=4, w=2, x=1
- 7 = rwx
- read + write + execute (4+2+1)
- 6 = rw-
- read + write, no execute (4+2)
- 5 = r-x
- read + execute, no write (4+1)
- 755
- rwxr-xr-x: owner full, group and others read+execute — programs and directories
- 644
- rw-r--r--: owner writes, everyone reads — ordinary files
- 600
- rw-------: owner only — secrets and private keys
| Task | Command | Notes |
|---|---|---|
| Programs and directories | chmod 755 deploy.sh | rwxr-xr-x — owner manages, everyone else can run or enter |
| Ordinary readable files | chmod 644 index.html | rw-r--r-- — the default-looking mode for content |
| Owner-only directory | chmod 700 ~/.ssh | rwx------ — sshd refuses looser modes on this path |
| Private keys and secrets | chmod 600 ~/.ssh/id_ed25519 | rw------- — OpenSSH rejects group/world-readable keys outright |
| AVOID: world-writable | chmod 777 file | any user may replace or plant content; fix owner/group instead — 777 is almost never the right answer |
| Directories only, recursively | sudo find /var/www -type d -exec chmod 755 {} + | {} + batches many files per chmod — faster than the \; variant |
| Files only, recursively | sudo find /var/www -type f -exec chmod 644 {} + | pairs with the directory row; shortcut: chmod -R u=rwX,go=rX /var/www |
| Exact read-only for everyone | chmod a=r report.md | sets the mode precisely — strips write and execute in one stroke |
Symbolic chmod: adjust in place
Syntax: who(+/-/=what) — u owner, g group, o others, a all; + adds, - removes, = sets exactly
- chmod +x deploy.sh
- add execute for everyone — the everyday script enabler
- chmod u+x ~/bin/check.sh
- execute for the owner only
- chmod go-w /srv/www
- take write away from group and others, leave the rest untouched
- chmod go-rwx secret.env
- strip group and others to nothing — equals 700
- chmod u=rwx,g=rx,o=
- set each class exactly; o= removes all bits for others — equals 755
- capital X
- chmod -R u=rwX,go=rX dir — execute lands on directories and already-executable files only, never on plain data files
Ownership: chown and friends
| Task | Command | Notes |
|---|---|---|
| Change the owner | sudo chown alice report.md | takes user or UID |
| Owner and group together | sudo chown alice:developers report.md | the common web-app fix in one call |
| Group only, owner kept | sudo chown :developers report.md | empty user side skips the owner |
| chgrp shorthand | chgrp developers report.md | non-root works only into groups you are a member of |
| Recurse a whole tree | sudo chown -R www-data:www-data /var/www/app | double-check the path — a typo with -R is expensive |
| Inspect like ls -l, precisely | stat -c '%A %a %U:%G %n' report.md | symbolic, octal, owner:group, name — GNU stat specifiers |
Special bits and umask
| Task | Command | Notes |
|---|---|---|
| Show current umask | umask | prints four octal digits, e.g. 0022 — leading 0 marks octal |
| Set default permissions | umask 022 | masks bits from the 666/777 baselines: new files 644, new dirs 755; persists via shell profile |
| SUID: run as the file's owner | sudo chmod u+s /usr/local/bin/tool | mode 4755, shown as -rwsr-xr-x; passwd is the classic legitimate user — treat custom SUID binaries as attack surface |
| Audit SUID binaries | sudo find / -xdev -perm -4000 -type f | compare against a fresh distro install; investigate every stray — privilege escalation loves forgotten SUID |
| SGID on a shared directory | sudo chmod g+s /srv/team | mode 2775: files created inside inherit the directory's group, not the creator's — team-share glue |
| Sticky bit on a shared directory | sudo chmod +t /srv/pubdrop | mode 1777, shown as drwxrwxrwt: users may delete only their own files — the /tmp model |
ACLs: finer-grained grants
| Task | Command | Notes |
|---|---|---|
| View a file's ACL | getfacl /srv/project | lists owner, group, named entries and the effective mask |
| Grant a named user | setfacl -m u:bob:rx /srv/project | -m modifies; bob gains read+execute without joining the group |
| Revoke one entry | setfacl -x u:bob /srv/project | -x removes the named-user line, leaving others intact |
| Inheritable grant for new files | sudo setfacl -d -m u:deploy:rx /srv/releases | -d sets a default ACL on the directory; newly created children inherit automatically — repeat per pre-existing subdirectory |
FAQ
What does chmod 755 mean?
Three octal digits, one per class: owner, group, others. Each digit sums read=4, write=2, execute=1. So 755 unpacks to 7=4+2+1 (rwx) for the owner, 5=4+1 (r-x) for the group, 5=4+1 (r-x) for others — owner fully manages the file, everyone else may read and run it but not modify it. That is why 755 is the standard mode for programs and directories, while 644 (rw-, r--, r--) suits ordinary files nobody needs to execute.
When do I need 600 instead of 644?
Whenever others must not even read the file. 644 lets every local user read the contents; 600 restricts everything but the owner. Private keys, credential files, .env files and database dumps belong at 600 (and their containing directories at 700, so listings are hidden too). OpenSSH enforces this: it refuses to use a private key that group or others can read, reporting UNPROTECTED PRIVATE KEY FILE.
What does umask do?
umask subtracts permission bits from everything you newly create. Files start from a 666 baseline and directories from 777, and the mask removes bits: umask 022 strips write for group and others, producing 644 files and 755 directories. The common values: 022 (standard, others can read), 077 (private — 600 files, 700 dirs, right for multi-user shells), 002 (group-writable, common on shared-dev setups). Set it per-session with umask 022 or persistently in ~/.bashrc or /etc/profile.
What does the sticky bit do on a directory?
It lets many users write into a shared directory while allowing each of them to delete or rename only their own files — write without delete rights over neighbors. /tmp is the canonical example: mode 1777, displayed as drwxrwxrwt with the t flag. Apply it with chmod +t /dir (or the leading digit: chmod 1777 /dir) on any drop-box-style share; without it, anyone who can write to the directory can remove everyone's files.
What is SUID and is it safe?
SUID (set-user-ID, mode 4000, shown as an s in the owner's execute slot) makes a program execute with the identity of its file owner — typically root — no matter who runs it. It is how /usr/bin/passwd lets ordinary users edit /etc/shadow. Legitimate uses are narrow and carefully audited system binaries; every additional SUID binary is a standing privilege-escalation opportunity, so review periodically with sudo find / -xdev -perm -4000 -type f and treat unexpected results as incidents. Note the bit does nothing on shell or interpreted scripts — Linux ignores SUID on them.
Related tools
- IPv4 subnet calculator — break any CIDR block into network, range, broadcast and usable hosts.
- IP range to CIDR — turn an arbitrary address range into its minimal covering CIDR blocks.
- VLSM calculator — split a block into right-sized subnets by host requirements.