Understanding Linux File Permissions: chmod, chown, and umask Explained
A practical walkthrough of Linux permission bits, ownership, symbolic and numeric chmod modes, plus how umask quietly decides the permissions on everything you create.

You run ls -l, see something like -rw-r--r--, and move on. That string is a contract between the kernel and every process on the machine, and it decides who can read your SSH keys, who can edit a config file, and whether a web server can even open the directory it serves. Once you can read that string fluently, a whole class of "permission denied" problems stops being mysterious.
Reading the Permission String
The ten characters printed by ls -l are three things stacked together. The first character is the file type: - for a regular file, d for a directory, l for a symbolic link. The remaining nine characters are three triplets, in this order: the owner, the group, and everyone else.
Inside each triplet, the letters mean what you'd expect, and a dash means that bit is off:
- r — read. For a file, open and read contents. For a directory, list names inside it.
- w — write. For a file, modify contents. For a directory, create, rename, or delete entries inside it.
- x — execute. For a file, run it as a program or script. For a directory, enter it and follow paths through it.
So -rw-r--r-- is a regular file the owner can read and write, while group members and everyone else can only read it. That is the classic mode for documents and configuration files, and it is what you get by default on most systems.
Numeric and Symbolic Modes
Each permission bit has a value: read is 4, write is 2, execute is 1. Add them within a triplet and you get a digit from 0 to 7. Three digits, one per triplet, give you the familiar shorthand.
- 644 — owner read/write, group read, others read. Standard for files.
- 600 — owner only. Standard for private keys and secrets.
- 755 — owner full control, everyone else read and execute. Standard for directories and public scripts.
- 700 — owner only, but with execute. Common for ~/.ssh.
- 664 and 775 — the group-writable variants, handy on shared project directories.
There is a fourth digit you will occasionally see in front: setuid (4), setgid (2), and the sticky bit (1). 1777 on /tmp is the sticky bit, which stops users from deleting each other's files in a shared directory. You rarely need to set these by hand, but you should recognize them when you see a lowercase s or a t in the permission string.
chmod Without Breaking Things
chmod changes the mode. Numeric mode is compact and absolute; symbolic mode is relative and easier to reason about when you only want to adjust one thing.
chmod 640 notes.txt # exact mode chmod u+x deploy.sh # add execute for the owner chmod go-w report.md # remove write for group and others chmod a+r shared.log # add read for everyone chmod -R 755 /srv/app/public # recursiveThe letters are u (owner), g (group), o (others), and a (all). The operators are + to add, - to remove, and = to set exactly. A capital X is worth knowing: chmod -R a+X some-tree adds execute only to directories, and to files that already had some execute bit. That single command fixes a lot of extracted archives without turning every text file into a fake program.
Recursive changes deserve caution. Where you need different modes for files and directories, find is safer than a blanket -R:
find . -type f -exec chmod 644 {} + find . -type d -exec chmod 755 {} +Avoid chmod -R 777 in any form. It hands write access to every account on the machine, and on a directory it lets anyone rename or delete files they have no business touching. It is almost never the fix, even when it appears to make an error message go away.
chown and chgrp: Who Owns This
Every file has one owning user and one owning group. chown changes both, chgrp changes only the group. Both normally require root, because giving away ownership of your own files is a privilege escalation primitive.
sudo chown alice report.pdf sudo chown alice:developers /srv/project sudo chgrp -R www-data /var/www/site sudo chown --reference=/etc/nginx/nginx.conf new.confCheck your own identity and group memberships with id before you debug access: a user may be blocked simply because they are not in the group that owns the file. The --reference flag is a quiet favorite, since it copies ownership and mode from an existing file rather than making you retype them.
Directories Are Their Own Game
Directory permissions trip people up because x is not about running anything. On a directory, x means traverse: without it you cannot cd into the directory or reach any file inside, even if you know the full path. r lets you list names, and w lets you add or remove entries.
The consequence is worth remembering: deleting a file depends on write permission on the directory, not on the file itself. A file owned by root inside a directory you own can be removed by you. That is also why the sticky bit exists.
umask: The Defaults Nobody Sets Explicitly
When a program creates a file, the kernel starts from a base mode — 666 for files, 777 for directories — and subtracts the bits in your umask. The umask is a mask, not a mode: it lists permissions that should not be granted.
With the common umask of 022, a new file becomes 644 and a new directory becomes 755. With a stricter umask of 027, they become 640 and 750. Note that umask can never add execute to a new file, because files never start with it.
- Check the current value with umask (it prints 0022).
- Set it for the session with umask 027.
- Make it permanent by adding the same line to ~/.bashrc or ~/.profile.
- Set a system-wide default in /etc/profile or a drop-in file under /etc/profile.d/.
A Practical Checklist for Real Work
When permissions bite, work from evidence rather than guesses. Run ls -ld /path/to/dir to see the directory itself instead of its contents, and namei -l /var/www/site/index.html to trace every directory along the path and spot the one missing an x. stat -c '%a %U %G %n' file prints mode, owner, and group in one line, which is ideal for comparing a broken file against a working one.
For SSH, keep ~/.ssh at 700, private keys at 600, and authorized_keys at 600. For web roots, prefer group ownership with chown -R user:www-data and modes like 750 or 640 over anything world-writable. Change one thing at a time, test immediately, and keep a note of what you changed. Permission work is reversible, but only if you remember the original state.
Photo: Nathaniel Tang / Pexels




