Linux User and File Permissions Cheat Sheet
Read ls -l output, understand permission classes and octal modes, use chmod and chown safely, and work with SUID, SGID, sticky bit, umask and ACLs.
A practical reference for Linux users, groups, and file permissions: reading ls -l, changing modes with chmod, ownership with chown/chgrp, special permissions, umask, and troubleshooting access problems.
1. Reading ls -l output
ls -l deploy.sh
-rwxr-xr-- 1 alex developers 4096 Sep 12 10:30 deploy.sh
| Field | Value | Meaning |
|---|---|---|
- | file type | regular file (see the type table below) |
rwx | owner permissions | alex can read, write, execute |
r-x | group permissions | developers can read, execute, not write |
r-- | other permissions | everyone else can only read |
1 | hard-link count | number of hard links pointing to this file |
alex | owner | the user who owns the file |
developers | group | the group that owns the file |
4096 | size | file size in bytes |
Sep 12 10:30 | modification time | when the content was last changed |
deploy.sh | name | the file or directory name |
File type characters
The first character of the ten-character permission string identifies the type:
| Character | Type |
|---|---|
- | Regular file |
d | Directory |
l | Symbolic link |
c | Character device (e.g. /dev/tty) |
b | Block device (e.g. /dev/sda) |
s | Socket |
p | Named pipe (FIFO) |
2. Permission classes and basic permission bits
Three classes, each with three possible bits:
u— user/ownerg— groupo— othersa— all three classes at once (used withchmod, not shown byls -l)
Each class has:
r— readw— writex— execute-— that permission is denied
-rwxr-xr--
^^^ ^^^ ^^^
user group other
Files vs. directories: the same letters mean different things
| Bit | On a file | On a directory |
|---|---|---|
r | Read the file’s contents | List the names of entries in the directory (ls) |
w | Modify the file’s contents | Create, delete, or rename entries inside the directory |
x | Execute the file (script/binary) | “Search”/traverse the directory — required to cd into it or access anything inside by path, even if you know the exact name |
Two important nuances:
- Write on a directory controls the directory’s contents, not the files themselves. A user with write access to a directory can delete or rename a file inside it even if they don’t own that file and can’t write to it directly — permissions on the file don’t protect it from this.
- A directory needs
xat every level of the path to reach anything inside it. If any parent directory in the path is missingxfor you, you cannot access the file underneath, regardless of that file’s own permissions or even a generous ACL on it.
3. Octal permissions
Each permission bit has a numeric value:
r = 4
w = 2
x = 1
Add the values for each class to get one digit; three digits cover user, group, other.
| Mode | Symbolic | Typical use |
|---|---|---|
777 | rwxrwxrwx | Everyone can read, write, execute — almost never appropriate |
755 | rwxr-xr-x | Executables and directories others should be able to use but not modify |
750 | rwxr-x--- | Executable/directory usable by the owner and group only |
700 | rwx------ | Private executable/directory, owner only |
666 | rw-rw-rw- | Readable/writable by everyone — rarely correct for a file |
664 | rw-rw-r-- | Group-shared file, others can read |
660 | rw-rw---- | Group-shared file, no access for others |
644 | rw-r--r-- | Common default for regular files (owner edits, everyone reads) |
640 | rw-r----- | Readable by owner and group only, e.g. a config file with secrets |
600 | rw------- | Private file, owner only — SSH keys, credentials |
400 | r-------- | Read-only, owner only — an extra safeguard against accidental edits |
777means anyone on the system can read, overwrite, or (if it’s a script/binary) execute the file. It is almost never the right fix. If something “isn’t working” because of a permission error, find out what access is actually missing instead of opening everything up.
4. chmod
Symbolic syntax
chmod u+x script.sh # add execute for the owner
chmod g-w file.txt # remove write for the group
chmod o-r file.txt # remove read for others
chmod u=rw,g=r,o= file.txt # set owner rw, group read-only, others nothing
Numeric syntax
chmod 644 file.txt # rw-r--r--
chmod 755 script.sh # rwxr-xr-x
chmod 700 private-key.pem # rwx------
Recursive changes — and their risk
chmod -R 750 shared-directory/
-R applies the same mode to every file and subdirectory underneath. That’s the problem: directories and files usually need different permissions. A directory typically needs x to be traversable; most regular files should not be executable. Running a single recursive chmod mode over a mixed tree either:
- makes ordinary files executable when they shouldn’t be (using a directory-appropriate mode like
750on everything), or - strips the
xa directory needs to be entered (using a file-appropriate mode like640on everything).
Safer approach — set directories and files separately:
find shared-directory/ -type d -exec chmod 750 {} +
find shared-directory/ -type f -exec chmod 640 {} +
This gives directories the traversal bit they need while keeping regular files non-executable.
5. Ownership and groups
Inspecting identity and ownership
whoami # the current user
id # current user, uid, group, gid, and all group memberships
groups # groups the current user belongs to
ls -l file.txt # owner and group of a file
stat file.txt # detailed metadata: owner, group, permissions, timestamps, inode
Changing ownership
chown alex file.txt # change the owner only
chown alex:developers file.txt # change owner and group together
chgrp developers file.txt # change the group only
sudo chown -R alex:developers project/ # recursively re-own a project directory
Be careful with recursive ownership changes in system locations such as
/,/etc,/usr,/var, or an application’s installation directory. Re-owning files a service or package manager expects to be owned byroot(or another system account) can break that service, break future package upgrades, or open a security hole. Scopechown -Rnarrowly — to a specific project or data directory you manage — and double-check the path before running it.
6. Special permissions
Beyond the standard rwx bits, three special permissions change behavior:
- SUID (Set User ID) — on an executable, the program runs with the privileges of the file’s owner, not the user who launched it. Classic example:
/usr/bin/passwdruns as root so an ordinary user can update/etc/shadow. - SGID (Set Group ID) — on an executable, it runs with the file’s group privileges. On a directory, new files and subdirectories created inside automatically inherit that directory’s group, instead of the creating user’s primary group — the standard way to make a shared team directory actually stay shared.
- Sticky bit — on a directory, only the file’s owner (or root) can delete or rename it, even if others have write access to the directory. Used on world-writable shared directories like
/tmpso users can’t delete each other’s files.
chmod 4755 program # SUID + rwxr-xr-x
chmod 2775 shared-directory # SGID + rwxrwsr-x
chmod 1777 shared-temporary-directory # sticky + rwxrwxrwt
The leading digit is the special-bit sum: SUID = 4, SGID = 2, sticky = 1 (combine as needed, e.g. 6 for SUID+SGID).
SUID needs special care. A SUID binary — especially one owned by
root— runs with elevated privileges regardless of who invokes it, so a bug or a misconfigured SUID program is a direct path to privilege escalation. Only set SUID on binaries that specifically require it, never as a shortcut to work around a permissions error, and periodically audit for unexpected SUID files:find / -perm -4000 -type f 2>/dev/null.The sticky bit is why
/tmpworks as a shared directory. Without it, anyone with write access to/tmp(i.e. everyone) could delete or rename any other user’s temporary files.
7. Immutable and other file attributes (chattr/lsattr)
chmod/chown control who can access a file. File attributes set with chattr work underneath that layer entirely, and can block an action even for root.
lsattr file.txt # show the attributes currently set on a file
sudo chattr +i file.txt # make it immutable - can't be modified, deleted, renamed, or linked, not even by root
sudo chattr -i file.txt # remove the immutable flag again
To actually delete an immutable file, removing the flag is a required first step - rm alone will never work on it, no matter who runs it:
sudo chattr -i file.txt # remove the immutable flag - this step can't be skipped
rm file.txt # now the normal delete works
| Flag | Effect |
|---|---|
i | Immutable - no modifying, deleting, renaming, or linking the file until the flag is removed, regardless of permissions or ownership |
a | Append-only - can be opened for writing only in append mode, so existing content can’t be edited or truncated (useful for logs) |
u | Undeletable - the filesystem tries to preserve the content after deletion, for recovery (support varies by filesystem; don’t rely on it as a backup strategy) |
rm: cannot remove 'file.txt': Operation not permitted, on a file wherels -lshows you have every permission you need, is the classic sign of the immutable attribute - checklsattr file.txtbefore assuming it’s a permissions or ownership problem.
chattr/lsattronly work on filesystems that support extended attributes (ext2/3/4, XFS, Btrfs) - they’re a no-op on FAT/exFAT and similar.
8. umask
umask sets the permission bits that are removed from the default when a new file or directory is created — it doesn’t grant permissions, it subtracts them.
umask # show the current umask
umask 022 # set it for the current shell session
umask 027 # a stricter umask
New files start from a base of 666 (rw-rw-rw-, never executable by default, regardless of umask) and new directories from 777 (rwxrwxrwx). The umask is subtracted from that base:
| umask | New file mode | New directory mode |
|---|---|---|
022 | 644 (rw-r--r--) | 755 (rwxr-xr-x) |
027 | 640 (rw-r-----) | 750 (rwxr-x---) |
077 | 600 (rw-------) | 700 (rwx------) |
022 is a common default (owner can edit, everyone can read). 027/077 are stricter choices for shared or sensitive systems where group or other access shouldn’t be granted automatically.
9. Practical scenarios and troubleshooting
Make a shell script executable:
chmod +x deploy.sh
./deploy.sh
Secure a private SSH key:
chmod 600 ~/.ssh/id_ed25519
SSH clients refuse to use a private key that’s readable by group or others — this is required, not just good practice.
Create a group-shared directory with SGID, so it stays shared:
sudo mkdir /srv/team-share
sudo chgrp developers /srv/team-share
sudo chmod 2775 /srv/team-share
Find files owned by a specific user:
find /home -user alex -type f 2>/dev/null
Check why a user can’t access a file:
id # confirm the user's uid/gid and group memberships
ls -l /path/to/file # owner, group, and mode of the file itself
groups alex # is alex actually in the group that owns the file?
Check parent-directory permissions — remember every directory in the path needs x for you:
ls -ld / /home /home/alex /home/alex/project
Walk the whole path at once with namei -l, where available:
namei -l /home/alex/project/deploy.sh
This prints the permissions of every component of the path in one pass, making a missing x on a parent directory immediately obvious.
A file won’t delete or edit despite correct permissions and ownership:
lsattr /path/to/file # check for the immutable attribute before suspecting permissions/ownership
Check ACLs if owner/group/other permissions don’t explain the access you’re seeing:
getfacl file.txt
A
+at the end of the permission string inls -loutput (e.g.rwxr-x---+) means the file has an ACL granting additional per-user or per-group permissions beyond the standard three classes. ACLs are an advanced topic beyond this sheet’s scope —getfacl/setfaclare the tools to reach for when standard permissions genuinely aren’t enough (e.g. one extra user needs access without changing the file’s group).
10. Security best practices
- Use least privilege. Grant only the access actually needed — start narrow and add permissions when a real need appears, rather than starting broad and hoping nothing goes wrong.
- Avoid
chmod 777. It is almost never the correct fix; if a permission error shows up, find the specific missing bit instead. - Prefer group-based sharing over world-writable files. Add the right users to a group and use
770/2775-style modes instead of making something writable by everyone. - Protect SSH keys and sensitive configuration. Private keys and files containing credentials should be
600(or400), owned by the account that actually needs them. - Check ownership and parent-directory permissions before changing modes. A permission problem is often actually an ownership problem, or a missing
xseveral directories up — confirm the real cause before reaching forchmod. - Test permission changes as a non-privileged user when possible. Verifying access as the actual account that needs it (or with
sudo -u) catches mistakes that testing as root would silently hide.