Quick Reference
Permission Model
Owner · Group · Others
Basic Bits
r (4) · w (2) · x (1)
Special Bits
SUID · SGID · Sticky
The Permission String
Every file and directory has a 10-character permission string visible in ls -l output. Understanding how to read it is the foundation of Linux permissions.
Example: -rwxr-xr--
–
rwx
r–x
r––
File type (- = file, d = directory, l = symlink)
Owner permissions: rwx = read + write + execute
Group permissions: r-x = read + execute, no write
Others permissions: r– = read only
| Character | Position | Meaning |
- | 1 | Regular file |
d | 1 | Directory |
l | 1 | Symbolic link |
c | 1 | Character device (e.g. /dev/tty) |
b | 1 | Block device (e.g. /dev/sda) |
r | 2, 5, 8 | Read permission |
w | 3, 6, 9 | Write permission |
x | 4, 7, 10 | Execute permission |
- | any | Permission not set |
s | 4 or 7 | SUID (pos 4) or SGID (pos 7) with execute |
S | 4 or 7 | SUID or SGID set but execute bit is NOT set |
t | 10 | Sticky bit set, execute bit set |
T | 10 | Sticky bit set, execute bit NOT set |
Permission Bits & Octal Notation
Each permission triplet (owner, group, others) is represented as a 3-bit binary number, written as a single octal digit. This is the basis of numeric chmod.
| Binary | Octal | Symbolic | Permissions |
000 | 0 | --- | None |
001 | 1 | --x | Execute only |
010 | 2 | -w- | Write only |
011 | 3 | -wx | Write + execute |
100 | 4 | r-- | Read only |
101 | 5 | r-x | Read + execute |
110 | 6 | rw- | Read + write |
111 | 7 | rwx | Read + write + execute (full) |
Common Octal Combinations
| Octal | Symbolic | Typical Use |
400 | r-------- | Read-only by owner only (e.g. private key backup) |
600 | rw------- | Read/write by owner only — SSH private keys |
640 | rw-r----- | Owner read/write, group read — config files |
644 | rw-r--r-- | Owner read/write, everyone read — web files, configs |
664 | rw-rw-r-- | Owner and group read/write — shared project files |
700 | rwx------ | Full access for owner only — private scripts |
750 | rwxr-x--- | Owner full, group execute — team scripts |
755 | rwxr-xr-x | Owner full, everyone read/execute — directories, public scripts, binaries |
775 | rwxrwxr-x | Owner and group full — shared directories |
777 | rwxrwxrwx | Full access for everyone — avoid in production |
Never use 777 in production. Setting chmod 777 on files or directories grants any user on the system full read, write, and execute access. On web servers this is especially dangerous — any PHP/Python process can overwrite your files. Use 755 for directories and 644 for files as a baseline.
chmod — Change Permissions
Numeric (Octal) Mode
| Command | What It Does |
chmod 644 file.txt | Owner rw, group r, others r |
chmod 755 script.sh | Owner rwx, group rx, others rx |
chmod 600 ~/.ssh/id_rsa | SSH private key — owner rw only |
chmod 700 ~/.ssh | SSH directory — owner only |
chmod 000 file.txt | No permissions for anyone (even owner needs sudo to read) |
chmod -R 755 /var/www/html | Apply recursively to directory and all contents |
Symbolic Mode
Symbolic mode uses letters to add (+), remove (-), or set (=) permissions without specifying all bits at once.
| Who | Operator | Permission | Meaning |
u | User (owner) |
g | Group |
o | Others |
a | All (u + g + o) |
| + | Add permission |
| - | Remove permission |
| = | Set exactly (replaces existing) |
| Command | What It Does |
chmod +x script.sh | Add execute for owner, group, and others |
chmod u+x script.sh | Add execute for owner only |
chmod g+w file.txt | Add write permission for group |
chmod o-r file.txt | Remove read permission from others |
chmod a-x file.txt | Remove execute from everyone |
chmod u=rwx,g=rx,o=r file.txt | Set exact permissions for each class |
chmod g=u file.txt | Copy owner permissions to group |
chmod u-s file | Remove SUID bit from file |
chmod -R a+rX /srv/shared | Recursively add read; add execute only to directories (X) |
Capital X vs lowercase x: chmod +x adds execute to all files including regular files. chmod +X (capital X) adds execute only to directories and files that already have execute set for someone. Use chmod -R a+rX when making a directory tree readable — it avoids making regular files executable.
chown & chgrp — Change Ownership
| Command | What It Does |
chown alice file.txt | Change owner to alice |
chown alice:developers file.txt | Change owner to alice AND group to developers |
chown :developers file.txt | Change group only (owner unchanged) |
chown -R www-data:www-data /var/www/html | Recursively change owner and group |
chown --reference=ref.txt target.txt | Copy ownership from another file |
chgrp developers file.txt | Change group to developers |
chgrp -R developers /srv/project | Recursively change group |
ls -l file.txt | Show owner and group |
stat file.txt | Show full file metadata including ownership and octal permissions |
Viewing numeric UID/GID: ls -ln shows numeric user and group IDs instead of names. Useful when UIDs don’t resolve to names (e.g. on NFS mounts or in containers).
Special Permission Bits
Three additional bits — SUID, SGID, and Sticky — control advanced privilege and sharing behaviour. They are set as a 4th octal digit (leading digit).
| Bit | Octal | On File | On Directory | Visible As |
| SUID |
4xxx |
File runs with the owner’s privileges, not the caller’s |
Ignored (on most Linux) |
s or S in owner execute position |
| SGID |
2xxx |
File runs with the group’s privileges |
New files inherit the directory’s group (not creator’s) |
s or S in group execute position |
| Sticky |
1xxx |
Ignored on modern Linux |
Only the file owner (or root) can delete/rename files inside |
t or T in others execute position |
Examples in the Wild
| Path | Permissions | Bit | Why It’s Set |
/usr/bin/passwd | -rwsr-xr-x | SUID | Runs as root so any user can change their own password (writes to /etc/shadow) |
/usr/bin/sudo | -rwsr-xr-x | SUID | Must run as root to grant elevated privileges |
/usr/bin/ping | -rwsr-xr-x | SUID | Requires raw socket access (root on older systems) |
/tmp | drwxrwxrwt | Sticky | Anyone can create files; only owner can delete their own files |
/var/mail | drwxrwsr-x | SGID | New mail files inherit group mail regardless of creator |
Setting Special Bits
| Command | What It Does |
chmod u+s /usr/local/bin/mytool | Set SUID on file |
chmod 4755 /usr/local/bin/mytool | Set SUID + 755 permissions (numeric) |
chmod g+s /srv/shared | Set SGID on directory |
chmod 2775 /srv/shared | Set SGID + 775 (numeric) |
chmod +t /tmp/mydir | Set sticky bit on directory |
chmod 1777 /tmp/mydir | Set sticky + 777 (numeric) |
chmod u-s file | Remove SUID |
chmod g-s dir | Remove SGID |
SUID security risk: SUID binaries run with the file owner’s privileges. A SUID root binary with a vulnerability can be exploited to gain root. Regularly audit SUID files: find / -perm -4000 -type f 2>/dev/null. Any unexpected SUID binary is a red flag.
umask — Default Permission Mask
umask defines which permission bits are removed when new files and directories are created. It is subtracted from the maximum default (666 for files, 777 for directories).
| umask | New File Result | New Directory Result | Typical Use |
022 | 644 (rw-r–r–) | 755 (rwxr-xr-x) | Default on most Linux systems |
027 | 640 (rw-r—–) | 750 (rwxr-x—) | Servers — group readable, no access for others |
077 | 600 (rw——-) | 700 (rwx——) | High-security — owner only |
002 | 664 (rw-rw-r–) | 775 (rwxrwxr-x) | Shared development environments |
| Command | What It Does |
umask | Show current umask value |
umask 027 | Set umask for current session |
umask -S | Show umask in symbolic format (u=rwx,g=rx,o=) |
umask is not subtraction — it is a bitmask. For files: new permissions = 666 AND (NOT umask). For directories: 777 AND (NOT umask). umask 022 means “mask out write for group and others.” The result is 644 for files and 755 for directories.
To make the change permanent, add umask 027 to ~/.bashrc, ~/.profile, or /etc/profile.
Finding Files by Permission
| Command | What It Finds |
find / -perm -4000 -type f 2>/dev/null | All SUID files (security audit) |
find / -perm -2000 -type f 2>/dev/null | All SGID files |
find / -perm -1000 -type d 2>/dev/null | All directories with sticky bit |
find /var/www -perm -o+w -type f | World-writable files under /var/www (security risk) |
find /etc -perm 777 2>/dev/null | Files with full 777 permissions in /etc |
find / -nouser 2>/dev/null | Files with no valid owner (orphaned files) |
find / -nogroup 2>/dev/null | Files with no valid group |
find /home -perm /o+rwx -not -type l 2>/dev/null | Files in /home accessible by others |
find . -perm -u+x -type f | Executable files in current directory tree |
find /etc -maxdepth 1 -perm -o+r -type f | Config files in /etc readable by others |
ACL — Access Control Lists
Standard Unix permissions allow only one owner and one group. ACLs extend this to grant access to arbitrary users and groups without changing ownership.
| Command | What It Does |
getfacl file.txt | Show ACL for a file |
setfacl -m u:alice:rw file.txt | Give alice read+write access |
setfacl -m g:developers:rx /srv/app | Give developers group read+execute on directory |
setfacl -m o::- file.txt | Remove all permissions for others via ACL |
setfacl -x u:alice file.txt | Remove ACL entry for alice |
setfacl -b file.txt | Remove all ACL entries (revert to standard permissions) |
setfacl -R -m g:developers:rx /srv/app | Apply ACL recursively |
setfacl -d -m g:developers:rx /srv/app | Set default ACL — new files inherit this ACL |
getfacl source.txt | setfacl --set-file=- target.txt | Copy ACL from one file to another |
ACL indicator: When a file has an ACL, ls -l shows a + at the end of the permission string, e.g. -rw-r--r--+. The filesystem must be mounted with acl option (ext4 and XFS support it by default on most distributions). Install tools with apt install acl or yum install acl.
Common Permission Recipes
Web Server (Nginx / Apache)
| Command | Purpose |
chown -R www-data:www-data /var/www/html | Set web server user as owner |
find /var/www/html -type d -exec chmod 755 {} \; | Directories: owner full, others read+execute |
find /var/www/html -type f -exec chmod 644 {} \; | Files: owner read/write, others read only |
chmod 750 /var/www/html/admin | Admin directory: no access for others |
SSH Keys
| Command | Purpose |
chmod 700 ~/.ssh | SSH directory — owner only (SSH will refuse to work otherwise) |
chmod 600 ~/.ssh/id_rsa | Private key — owner read/write only |
chmod 644 ~/.ssh/id_rsa.pub | Public key — readable by all |
chmod 600 ~/.ssh/authorized_keys | Authorized keys file |
chmod 644 ~/.ssh/known_hosts | Known hosts file |
chmod 600 ~/.ssh/config | SSH client config file |
Shared Directory for a Team
| Command | Purpose |
groupadd devteam | Create a shared group |
usermod -aG devteam alice | Add alice to the group |
mkdir /srv/project | Create shared directory |
chown root:devteam /srv/project | Assign group ownership |
chmod 2775 /srv/project | SGID + owner full + group full + others rx |
Why SGID on shared directories? Without SGID, files created inside /srv/project inherit the creator’s primary group — so alice’s files belong to alice and bob’s files belong to bob. With SGID set, all new files automatically inherit the devteam group, so everyone in the group can read and write them.
FAQ
What does execute permission mean on a directory?
On a directory, execute (x) means the ability to enter the directory and access files inside it — it is also called the “search” bit. Without execute on a directory you cannot cd into it, cannot access files inside it, and cannot traverse it in a path. You need execute on every directory in a file’s path to access the file. Read (r) on a directory means you can list its contents (ls). Write (w) means you can create, delete, and rename files inside it.
I own a file but cannot delete it. Why?
File deletion is controlled by the parent directory’s write permission, not the file’s own permissions. To delete a file you need write (w) and execute (x) on the directory that contains it. If the directory has the sticky bit set (t), you can only delete files you own — even if you have write permission on the directory. This is why you can’t delete other users’ files in /tmp.
What is the difference between chmod 755 and chmod u=rwx,go=rx?
They produce identical results — both set owner to rwx, group and others to rx. The numeric form is shorter and common in scripts and documentation. The symbolic form is more readable and safer for incremental changes: chmod +x script.sh adds execute without touching other bits, while chmod 755 script.sh sets all bits explicitly, potentially removing permissions you didn’t intend to change.
How do I safely apply permissions recursively without making all files executable?
Use two separate find commands: find /path -type d -exec chmod 755 {} \; for directories and find /path -type f -exec chmod 644 {} \; for files. Alternatively, use capital X: chmod -R a+rX /path — capital X adds execute only to directories and files that already have execute set for anyone, leaving regular files non-executable. Never use chmod -R 755 /path on a web directory — it makes every file executable.
Why does SSH refuse to connect when my key permissions are “too open”?
SSH deliberately refuses to use private keys that are accessible by other users — this is a security feature. The required permissions are: 700 on ~/.ssh, 600 on private keys (id_rsa, id_ed25519), and 600 on authorized_keys. If group or others have any read/write access to these files, SSH will display “Permissions 0644 for ‘id_rsa’ are too open” and refuse to use the key. Fix with chmod 600 ~/.ssh/id_rsa.
What is the difference between SUID and sudo?
SUID is a file permission bit — when set on an executable, it runs with the file owner’s UID regardless of who executes it. No configuration needed, no logging, no restrictions on what the binary can do. sudo is a program that allows specific users to run specific commands as another user (usually root), controlled by /etc/sudoers with full logging. For granting elevated access, always prefer sudo over SUID — sudo provides auditing, granular control, and can be revoked without touching file permissions.