What is chmod and how do Unix permissions work?
chmod ("change mode") is a POSIX command for setting file and directory permissions on Unix-like systems — Linux, macOS, BSD, WSL, even modern containers. The permission model dates to 1971's Unix V1 and has barely changed since: every file has an owner (user), a group, and rules for everyone else, with three permission bits each (read, write, execute). That's nine bits — three classes × three rights — neatly encoded in three octal digits.
This 9-bit model has survived 50+ years for a reason: it's just expressive enough to handle most real-world cases (config files, executables, web roots, log files) while being simple enough to reason about at a glance. Modern systems extended it with ACLs (access control lists), capabilities, AppArmor/SELinux, and namespaces — but plain chmod is still where 95% of permission decisions are made daily.
# ls -l output for a file
-rwxr-xr-- 1 anees devs 2048 Apr 30 12:34 deploy.sh
│└┬┘└┬┘└┬┘
│ │ │ └─── Others (everyone else): r-- = read only
│ │ └────── Group (devs): r-x = read + execute
│ └───────── Owner (anees): rwx = read + write + execute
└─────────── File type: - (regular file), d (directory), l (symlink)
The three classes — Owner, Group, Others
Every file has exactly three permission classes:
- Owner (user,
u) — the user who owns the file. Set bychown. By default, the user who created the file. - Group (
g) — the file's group. Members of this group get the group permissions. Set bychgrp. - Others (
o) — everyone on the system who isn't the owner and isn't in the group.
The shorthand a ("all") refers to all three classes simultaneously — chmod a+r file grants read to everyone.
The three permissions — Read, Write, Execute
| Bit | Symbol | Octal value | On a file | On a directory |
|---|---|---|---|---|
| Read | r | 4 | View file contents | List directory contents (ls) |
| Write | w | 2 | Modify or delete the file | Create / delete / rename entries inside |
| Execute | x | 1 | Run as a program | Enter the directory (cd); access entries by name |
Each class gets a 3-bit value combining its permissions: rwx = 4+2+1 = 7. r-x = 4+0+1 = 5. rw- = 4+2+0 = 6. The three octal digits combine all three classes: 755 = owner-rwx, group-rx, other-rx.
chmod 7XX = full owner access; chmod X75 = group can run/read; chmod XX0 = no access for "others". Memorize 4+2+1 once and you can read any chmod number forever.
Common chmod values — copy-paste cheatsheet
| Octal | Symbolic | Use case |
|---|---|---|
644 | rw-r--r-- | Standard file — owner can edit, others can read. Default for most documents, configs, web assets. |
755 | rwxr-xr-x | Standard directory or executable — owner has full control, others can read & traverse. Default for /var/www, scripts, binaries. |
600 | rw------- | Private file — only the owner can read or write. SSH private keys, auth tokens, secrets. |
700 | rwx------ | Private directory — only owner can enter and modify. ~/.ssh, home directories on multi-user systems. |
666 | rw-rw-rw- | World-writable file — anyone can edit. Almost always wrong; auditors flag this. |
777 | rwxrwxrwx | World-writable + executable — security disaster. NEVER use except for tmpfs or fully isolated containers. |
444 | r--r--r-- | Read-only for everyone — no writes even by the owner. Use for immutable configs. |
755 + setuid (4755) | rwsr-xr-x | Executable runs as the owner regardless of who launches it. Used by sudo, passwd. Rarely written by hand. |
2775 | rwxrwsr-x | Setgid directory — files created inside inherit the directory's group. Useful for shared team directories. |
1777 | rwxrwxrwt | Sticky bit — anyone can write, but only the owner can delete their own files. /tmp uses this. |
Octal vs symbolic notation — when to use each
Octal (numeric)
Three digits, fastest to type, sets all three classes at once. Best for setting fresh permissions from scratch.
chmod 755 deploy.sh # rwxr-xr-x
chmod 600 ~/.ssh/id_rsa # rw------- (SSH key)
chmod 644 *.html # rw-r--r-- (HTML files)
chmod -R 755 /var/www # recursive — entire directory tree
Symbolic (letter notation)
Letter codes for class (u/g/o/a) + operator (+/-/=) + permission (r/w/x). Best for tweaking existing permissions without touching others.
chmod +x script.sh # add execute for everyone (a+x is implied)
chmod u+x script.sh # add execute for owner only
chmod g-w shared.txt # remove write for group
chmod o=r config.yml # set others to read-only (clears w/x)
chmod a-w *.json # remove write for all classes
chmod u+rwx,g+rx,o-rwx file # combine multiple in one command
chmod -R u+w project/ # recursive: add owner-write everywhere
Rule of thumb: use octal for setting initial permissions, use symbolic for adjustments. The two are interchangeable — every chmod tool (including this calculator) shows both.
Special permission bits — setuid, setgid, sticky
Beyond the 9 standard bits, three special bits add advanced behaviors. They're encoded as a leading 4th octal digit (4000 = setuid, 2000 = setgid, 1000 = sticky), or set symbolically with u+s, g+s, +t.
| Bit | Octal | Symbolic | Effect on file | Effect on directory |
|---|---|---|---|---|
| setuid | 4xxx |
u+s (shows as s in user execute slot) |
Executable runs with owner's privileges (e.g. root) | Ignored on most Linuxes |
| setgid | 2xxx |
g+s (shows as s in group execute slot) |
Executable runs with group's privileges | New files inside inherit the directory's group (great for team folders) |
| sticky | 1xxx |
+t (shows as t in others execute slot) |
Historically: keep program in swap. Now: ignored. | Only the file owner can delete their own files (used by /tmp) |
Setuid in the wild
$ ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 232416 ... /usr/bin/sudo
↑
's' instead of 'x' = setuid set. sudo runs as root no matter who calls it.
Setuid binaries are an attack surface. A bug in a setuid program = local privilege escalation. Modern hardened systems use Linux Capabilities (per-process privilege flags) or SELinux/AppArmor instead. Don't add setuid to your own binaries unless you absolutely need it.
chmod in scripts — common patterns
Make a script executable
chmod +x deploy.sh # most common — adds x for all classes
chmod u+x deploy.sh # safer — only owner gets execute
./deploy.sh # now you can run it
Lock down SSH keys (mandatory for SSH to work)
chmod 700 ~/.ssh # directory: only owner can enter
chmod 600 ~/.ssh/id_rsa # private key: only owner reads/writes
chmod 644 ~/.ssh/id_rsa.pub # public key: anyone can read
chmod 600 ~/.ssh/authorized_keys # logins file: owner-only
chmod 600 ~/.ssh/known_hosts # known hosts: owner-only
Web server file permissions
# Standard pattern for Apache / nginx
chown -R www-data:www-data /var/www/site
find /var/www/site -type d -exec chmod 755 {} \; # directories
find /var/www/site -type f -exec chmod 644 {} \; # files
chmod 600 /var/www/site/.env # secrets file
Reset permissions on a freshly cloned repo
# Clear weird permissions inherited from Windows / archive
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
find . -name '*.sh' -exec chmod +x {} \; # restore script execute
Programmatic chmod in Python
import os, stat
# Set permissions (note: the leading 0o for octal literal)
os.chmod('deploy.sh', 0o755)
# Add execute permission without affecting others
current = os.stat('script.sh').st_mode
os.chmod('script.sh', current | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
chmod in Node.js
import { chmod } from 'node:fs/promises';
await chmod('deploy.sh', 0o755);
await chmod('id_rsa', 0o600); // private key
The umask — your default permission mask
When a process creates a new file, the OS doesn't grant arbitrary permissions — it starts from a "maximum" (666 for files, 777 for directories) and subtracts the bits in your umask. Common umask values:
| umask | New file permission | New directory permission | Use case |
|---|---|---|---|
022 | 644 | 755 | Default on most Linuxes — files readable by everyone, only owner writes. |
077 | 600 | 700 | Maximum privacy — only owner sees anything new. Default on multi-user shells like Tilde clubs. |
002 | 664 | 775 | Group-writable by default. Useful for shared development directories. |
027 | 640 | 750 | Group reads, others get nothing. Common on Debian for system files. |
# Check current umask
umask # → 0022 (the leading 0 is octal indicator)
# Set for current shell session
umask 077 # tighter — owner-only by default
# Set permanently in shell config
echo 'umask 022' >> ~/.bashrc
Best chmod calculator for 2026 — what to compare
Search results for "chmod calculator", "chmod 755 meaning", and "linux file permissions calculator" return a mix of static cheatsheets and interactive calculators. Three things separate the good from the noise: bidirectional conversion (octal ↔ symbolic both directions, not just one), special-bit support (setuid / setgid / sticky bit are missing from most), and whether the output is a copy-ready chmod command or just the permission string. Here is how the most-used chmod tools compare in 2026:
| Tool | Bidirectional | Special bits (4/2/1) | Copy-ready command | Recursive flag preview | Cost |
|---|---|---|---|---|---|
| FreeDevTool Chmod Calculator | Octal ↔ symbolic ↔ checkboxes | setuid + setgid + sticky | Yes | Yes (-R hint) | Free |
| chmod-calculator.com | Checkbox → octal | setuid + setgid only | Yes | No | Free, ad-funded |
| chmodcommand.com | Checkbox → octal | None | Yes | No | Free, ad-heavy |
| permissions-calculator.org | Checkbox → octal/symbolic | None | Partial | No | Free |
stat -c "%a" (CLI) | Read existing only | Yes | N/A (read tool) | N/A | Built-in |
| VS Code Remote-SSH file properties | Tree view only | Limited | No | No | Free |
What does chmod 755 mean and when should I use it?
chmod 755 sets these permissions: owner = rwx (read + write + execute = 4+2+1=7), group = r-x (read + execute = 4+0+1=5), others = r-x (read + execute = 5). The mnemonic is "owner can do everything, everyone else can read and run". Use 755 for: executable scripts and binaries in /usr/local/bin, web-accessible directories in Apache/nginx (so the web server can read+enter them), and shared utility scripts on a multi-user server. NOT for: regular text/data files (use 644), private SSH keys (use 600), files with sensitive info (use 600 owner-only). Common companion: chmod 644 for files inside a 755 directory — directory needs execute (to enter), files don't.
What's the difference between chmod, chown, and chgrp?
| Command | Changes | Example | Permission needed |
|---|---|---|---|
chmod | Permission bits (rwx for u/g/o + special) | chmod 755 file.sh | Owner of file or root |
chown | Owner (and optionally group) | chown alice file.txt | root only (most cases) |
chgrp | Group only | chgrp developers file.txt | Owner if member of target group, or root |
setfacl | Extended ACLs (per-user, per-group) | setfacl -m u:bob:rx file | Owner or root |
Decision rule: you want different permissions for different users beyond owner/group/others → setfacl. You want to give a different user ownership → chown. You want to change the file's group affiliation → chgrp. Everything else (changing read/write/execute on existing owner/group/others classes) → chmod.
Chmod calculator alternative to chmod-calculator.com — 4 reasons developers switched
- Bidirectional input. Type
755, pasterwxr-xr-x, or click checkboxes — all three update each other. Most calculators only accept one input direction. - Special bits surfaced as first-class. setuid (4000), setgid (2000), and sticky bit (1000) are checkboxes here, not buried in an "advanced" tab. Critical for shared upload directories (sticky on
/tmp) or wrapping a binary that needs root (setuid onpasswd). - Copy-ready chmod command with
-Rhint. Output is the fullchmod 755 file.shcommand, with a one-click toggle for recursive (-R). No mental concatenation required. - No ads, no popups. Tools indexed for "chmod calculator" almost universally inject ads or third-party tracking. This page is browser-only and persists nothing.
Pair the chmod calculator with the Cron Expression Parser for the other classic Linux DevOps cheat-sheet operation, the Git Cheatsheet for Git permission edge cases (Git tracks executable bit only), and the DevOps Tools hub for the broader Linux/CI toolkit.
chmod best practices — and what NOT to do
- Never
chmod 777in production. World-writable files are a major security hole. If a script "needs" 777 to work, the actual problem is wrong ownership (usechown) or wrong group membership. - Use
755for directories,644for files as your default. This is the standard pattern for web roots, project directories, and content trees. - Lock down secrets to
600. SSH keys,.envfiles, OAuth tokens, anything credential-like. SSH client refuses to use keys with permissions broader than600. - Use
findfor recursive permission changes.chmod -Rapplies the same mode to files AND directories, which is rarely what you want. Usefind -type d -exec chmod 755andfind -type f -exec chmod 644separately. - Audit setuid binaries. Run
find / -perm -u+s -type f 2>/dev/nullto find them. Each one is a potential privilege escalation path. Remove ones you don't need. - Set umask in your shell profile for consistent defaults. Don't rely on system defaults — they vary by distro.
- Use ACLs (
setfacl) for complex rules. If you need "user X can read but not write while group Y has full access", traditional chmod can't express it.setfaclcan. - Capabilities > setuid for new code. Linux Capabilities (
setcap cap_net_bind_service+ep myserver) grant fine-grained privileges without needing root. Modern alternative to setuid. - Don't forget the difference between file permissions and directory permissions. A file with
644inside a700directory is inaccessible to anyone but the directory's owner — directory permissions gate file access.