chmod (change mode) is the Linux command for changing file permissions. It works in two modes: symbolic mode uses letters like chmod u+x file (add execute for owner) or chmod go-w file (remove write for group and others), while numeric mode uses octal numbers like chmod 755 file (rwxr-xr-x) or chmod 644 file (rw-r–r–). To change permissions recursively for an entire directory, add the -R flag: chmod -R 755 directory/.
Introduction: Taking Control of File Permissions
You now know what Linux file permissions are — the nine bits that control read, write, and execute access for the owner, group, and others. But knowing what permissions mean and knowing how to change them are two separate skills. chmod is the command that bridges that gap.
chmod (change mode) is one of the most frequently used commands in Linux administration. You use it every time you write a shell script and need to make it executable. You use it to protect configuration files that contain passwords. You use it to set up shared directories where a team can collaborate. You use it during web server setup to ensure the right processes can read the right files. Understanding chmod thoroughly — both its modes, its syntax, and the judgment of which permissions to set — is a core Linux competency.
This article covers chmod completely: both notation systems (symbolic and numeric/octal), recursive permission changes, special permission bits (SetUID, SetGID, sticky bit), common real-world permission patterns, and how to avoid the most common chmod mistakes. By the end, you will be able to read any permission requirement and translate it into the right chmod command confidently.
chmod Basics: The Two Modes
chmod offers two completely different ways to specify permissions: symbolic mode (using letters) and numeric mode (using octal numbers). Both accomplish the same thing — setting permission bits — but each has advantages in different situations. Most experienced Linux users use both fluidly.
Symbolic Mode: Human-Readable Changes
Symbolic mode describes permission changes in terms of who, what operation, and which permissions:
chmod [who][operator][permissions] fileWho:
u— user (the file’s owner)g— group (the file’s associated group)o— others (everyone else)a— all (u + g + o combined)
Operator:
+— add the specified permission(s)-— remove the specified permission(s)=— set exactly these permission(s), removing all others for that class
Permissions:
r— readw— writex— executeX— execute only if the file is a directory or already has execute for someone (useful with-R)s— SetUID (foru) or SetGID (forg)t— sticky bit (foro)
Symbolic mode examples:
$ chmod u+x sc.ript.sh # Add execute for owner
$ chmod g-w shared_file.txt # Remove write for group
$ chmod o-r private.txt # Remove read for others
$ chmod a+r public_doc.pdf # Add read for everyone
$ chmod u+x,g+r new_sc.ript.sh # Multiple changes at once
$ chmod go-rwx secret.key # Remove all permissions for group and others
$ chmod u=rw,go=r config.txt # Set owner to rw, group and others to r
$ chmod a-x binary_data.bin # Remove execute from everyoneThe = operator is particularly useful for setting exact permissions without worrying about what was there before:
$ chmod u=rwx,g=rx,o=r sc.ript.sh # Precisely set all three classesNumeric Mode: Precise Octal Notation
Numeric mode expresses the complete permission set as a three-digit octal number. Each digit represents one permission class (owner, group, others), and each digit is the sum of the active permission bits:
- Read (r) = 4
- Write (w) = 2
- Execute (x) = 1
Calculate each digit by adding the values of the permissions you want:
| Permissions | Calculation | Digit |
|---|---|---|
rwx | 4+2+1 | 7 |
rw- | 4+2+0 | 6 |
r-x | 4+0+1 | 5 |
r-- | 4+0+0 | 4 |
-wx | 0+2+1 | 3 |
-w- | 0+2+0 | 2 |
--x | 0+0+1 | 1 |
--- | 0+0+0 | 0 |
A three-digit chmod command like chmod 754 file sets:
- Owner (7):
rwx(4+2+1) - Group (5):
r-x(4+0+1) - Others (4):
r--(4+0+0)
Numeric mode examples:
$ chmod 755 sc.ript.sh # rwxr-xr-x (standard executable)
$ chmod 644 document.txt # rw-r--r-- (standard file)
$ chmod 600 private.key # rw------- (private file)
$ chmod 700 secret_dir/ # rwx------ (private directory)
$ chmod 664 team_notes.txt # rw-rw-r-- (group-writable)
$ chmod 775 project_dir/ # rwxrwxr-x (group-writable directory)
$ chmod 400 readonly.conf # r-------- (read-only even for owner)
$ chmod 000 locked.txt # ---------- (no permissions for anyone)Which Mode to Use?
Use symbolic mode when:
- Making incremental changes to existing permissions (adding or removing specific bits)
- You do not want to affect permissions you are not explicitly changing
- Writing self-documenting scripts where the intent should be clear
$ chmod +x sc.ript.sh # Clear intent: make executable
$ chmod o-r private.txt # Clear intent: remove public readUse numeric mode when:
- Setting complete, absolute permissions from scratch
- You want to set all three permission classes precisely at once
- Speed matters — numeric mode is faster to type for common combinations
- Following documented permission requirements (documentation often specifies “set permissions to 644”)
$ chmod 755 sc.ript.sh # Fast, precise, exact
$ chmod 600 ~/.ssh/.id_rsa # Clear known-good patternViewing Current Permissions
Always check current permissions before and after changing them to confirm the result:
$ ls -la filename
-rw-r--r-- 1 sarah developers 2048 Feb 18 10:15 report.txt
$ chmod 664 report.txt
$ ls -la filename
-rw-rw-r-- 1 sarah developers 2048 Feb 18 10:15 report.txtThe permission string changed from -rw-r--r-- to -rw-rw-r--, confirming that group write was added successfully.
Using stat for Detailed Permission Information
$ stat report.txt
File: report.txt
Size: 2048 Blocks: 8 IO Block: 4096 regular file
Device: 802h/2050d Inode: 1234567 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ sarah) Gid: ( 1001/developers)
Access: 2026-02-18 10:15:22.000000000 +0000
Modify: 2026-02-18 10:15:22.000000000 +0000
Change: 2026-02-18 10:22:05.000000000 +0000stat shows both the octal form (0664) and symbolic form (-rw-rw-r--) of the current permissions — useful for translating between the two notations.
Recursive Permissions with -R
The -R (recursive) flag applies the permission change to a directory and all its contents — every file and subdirectory within it:
$ chmod -R 755 project/This sets 755 on the project/ directory itself, all files inside it, and all subdirectories and their contents.
The Problem with Naive Recursive chmod
Using a single permission set recursively on a directory often does the wrong thing for files. Directories need execute permission (to traverse into them), but regular files usually should not be executable:
$ chmod -R 755 website/This sets rwxr-xr-x on every file — including text files, images, and HTML files that should never be executable. This is unnecessary (harmless for most files but untidy) and potentially a security concern for web-served files.
The Right Approach: Separate File and Directory Permissions
Use find with -exec to apply different permissions to files and directories:
# Set directories to 755 (rwxr-xr-x)
$ find project/ -type d -exec chmod 755 {} +
# Set regular files to 644 (rw-r--r--)
$ find project/ -type f -exec chmod 644 {} +This cleanly separates concerns: directories get traversal permission, files get appropriate access without the execute bit.
For a group-collaborative setup:
# Directories: rwxrwxr-x (group can create/delete files)
$ find project/ -type d -exec chmod 775 {} +
# Files: rw-rw-r-- (group can read and write)
$ find project/ -type f -exec chmod 664 {} +The X Permission: Smart Execute
The uppercase X in symbolic mode adds execute permission only to:
- Directories (always)
- Files that already have execute permission set for at least one class
$ chmod -R a+X project/This adds execute where it makes sense (directories and already-executable files) without adding execute to regular data files. It is a cleaner recursive approach than simply using +x on everything.
Setting Special Permission Bits with chmod
Beyond the nine standard permission bits, chmod also sets the three special permission bits: SetUID, SetGID, and the sticky bit.
SetUID: Run as the File’s Owner
SetUID on an executable file causes it to run with the file owner’s permissions, not the caller’s:
Symbolic:
$ chmod u+s programNumeric: Add 4000 as a fourth (leading) digit:
$ chmod 4755 program # rwsr-xr-xThe s in the owner execute position confirms SetUID is set.
If the file does not have execute permission for the owner, the SetUID bit is shown as S (capital) instead of s:
$ chmod 4644 program # rwSr--r-- (SetUID set but no execute — unusual/unintended)SetGID: Inherit the File’s Group
SetGID on an executable runs with the file’s group identity. SetGID on a directory causes new files created in it to inherit the directory’s group rather than the creator’s primary group:
Symbolic:
$ chmod g+s directory/Numeric: Add 2000 as a leading digit:
$ chmod 2775 directory/ # rwxrwsr-xThe s in the group execute position confirms SetGID is set.
The complete collaborative directory setup with SetGID:
$ sudo mkdir /shared/project
$ sudo chown alice:developers /shared/project
$ sudo chmod 2775 /shared/project
$ ls -la /shared/
drwxrwsr-x 2 alice developers 4096 Feb 18 11:00 projectNow any developer who creates a file in /shared/project will have that file automatically owned by the developers group.
Sticky Bit: Protect Files in Shared Directories
The sticky bit on a directory means only the file’s owner (or root) can delete or rename files within it, even if the directory is world-writable. The /tmp directory uses this pattern:
Symbolic:
$ chmod o+t /shared/tmp_area/
$ chmod +t /shared/tmp_area/ # +t without specifying who also sets stickyNumeric: Add 1000 as a leading digit:
$ chmod 1777 /shared/tmp_area/ # rwxrwxrwtThe t in the others execute position confirms the sticky bit is set.
Using the Four-Digit Octal Form
For clarity and completeness, always use the four-digit form when setting special bits:
| Permission | Four-Digit | String |
|---|---|---|
| SetUID + rwxr-xr-x | 4755 | rwsr-xr-x |
| SetGID + rwxrwxr-x | 2775 | rwxrwsr-x |
| Sticky + rwxrwxrwx | 1777 | rwxrwxrwt |
| SetUID + SetGID | 6755 | rwsr-sr-x |
Three-digit commands like chmod 755 implicitly have a leading 0 (0755), meaning no special bits. Using chmod 2775 explicitly sets SetGID along with the standard permissions.
Common Permission Patterns and When to Use Them
644 — Standard File
$ chmod 644 document.txt # rw-r--r--Owner reads and writes. Group and others read only. The default permission for most personal files, documents, and configuration files you want others to be able to read.
600 — Private File
$ chmod 600 ~/.ssh/.id_rsa # rw-------Owner reads and writes only. No access for anyone else. Use for private keys, password files, and sensitive configuration.
755 — Standard Executable or Public Directory
$ chmod 755 sc.ript.sh # rwxr-xr-x
$ chmod 755 /var/www/html/ # rwxr-xr-xOwner has full access. Group and others can read and execute (traverse for directories). Use for programs meant for general use and public directories.
700 — Private Directory or Script
$ chmod 700 ~/private/ # rwx------
$ chmod 700 admin_sc.ript.sh # rwx------Only the owner can access. Use for directories with sensitive content and scripts only the owner should run.
664 — Group-Writable File
$ chmod 664 team_notes.txt # rw-rw-r--Owner and group members can read and write. Others can read. Use for files shared within a team where multiple people need to edit.
775 — Group-Writable Directory
$ chmod 775 /projects/team/ # rwxrwxr-xOwner and group members have full directory access. Others can read and traverse. Use for shared project directories.
770 — Private Group Directory
$ chmod 770 /projects/secret/ # rwxrwx---Owner and group members have full access. Others have no access. Use for directories where sensitive team content should not be publicly readable.
400 and 444 — Read-Only Files
$ chmod 400 important_archive.tar.gz # r--------
$ chmod 444 template.conf # r--r--r--400 — only the owner can read (maximum protection). 444 — everyone can read but nobody can write. Use for files that should never be modified accidentally.
chmod in Practice: Real-World Scenarios
Making a Script Executable
The most common chmod use case:
$ nano de.ploy.sh
# [write your script]
$ chmod +x de.ploy.sh # or chmod 755 deploy.sh
$ ./de.ploy.shWithout the chmod step, running ./de.ploy.sh produces “Permission denied” even though you own the file.
Fixing SSH Key Permissions
The SSH client refuses to use key files with overly permissive permissions:
$ chmod 700 ~/.ssh/ # SSH directory
$ chmod 600 ~/.ssh/.id_rsa # Private key
$ chmod 644 ~/.ssh/.id_rsa.pub # Public key (shareable)
$ chmod 600 ~/.ssh/.config # SSH config file
$ chmod 600 ~/.ssh/.authorized_keys # Authorized keys
After setting these, the SSH “UNPROTECTED PRIVATE KEY FILE” warning disappears.
Setting Up a Web Server Document Root
Web server files need to be readable by the web server process (www-data) but should not be world-writable:
$ sudo chown -R developer:www-data /var/www/html/
$ sudo find /var/www/html -type d -exec chmod 750 {} +
$ sudo find /var/www/html -type f -exec chmod 640 {} +Directories: 750 — developer has full control, www-data can read and traverse, others nothing. Files: 640 — developer can read/write, www-data can read (serve the files), others nothing.
Protecting a Configuration File with Secrets
$ sudo chmod 600 /etc/app/data.base.conf # rw-------
$ sudo chown appuser:appuser /etc/app/database.confOnly appuser (and root) can read the configuration containing the database password.
Setting Up a Shared Scratch Directory
A temporary work directory where multiple users can create files but cannot delete each other’s:
$ sudo mkdir /shared/scratch
$ sudo chmod 1777 /shared/scratch # rwxrwxrwtThe sticky bit (1777) allows anyone to create files but only the file’s owner can delete them — the same pattern used by /tmp.
chmod Pitfalls and How to Avoid Them
Pitfall 1: chmod -R with a Single Permission Set
The problem:
$ chmod -R 755 website/This sets execute permission on all files including HTML, CSS, images, and text files that should not be executable. While not dangerous for most files, it is messy and occasionally a security concern.
The solution: Use separate find commands for files and directories:
$ find website/ -type d -exec chmod 755 {} +
$ find website/ -type f -exec chmod 644 {} +Pitfall 2: Forgetting the Execute Bit on a Directory
$ chmod 644 mydir/This removes execute (traverse) permission from the directory. Now nobody (not even the owner) can cd into mydir/ or access files within it, even if those files have permissive permissions.
The solution: Directories almost always need execute permission: chmod 755 mydir/ not chmod 644 mydir/.
Pitfall 3: Making Files World-Writable
$ chmod 777 file.txt # DANGEROUSWorld-writable files (rwxrwxrwx) can be modified by any user on the system. This is almost never the right solution. If you need group sharing, use 664 or 775. If you need a world-writable area, use sticky bit (1777) on a directory.
Pitfall 4: Running chmod Recursively as Root Without Checking
$ sudo chmod -R 777 /important/system/directory/ # VERY DANGEROUSRunning chmod -R as root on the wrong directory can damage system files or security-sensitive files. Always double-check the path before running recursive chmod as root. Add --dry-run where supported, or use ls -la to preview the target first.
Pitfall 5: chmod Without Matching chown
Setting permissions on a file owned by the wrong user does not make it accessible. Permissions are evaluated relative to the file’s owner and group — if you own neither, only the “others” bits apply regardless of how permissive owner and group bits are.
Always consider whether chown or chgrp is also needed when fixing permission problems.
Quick Reference: chmod Cheat Sheet
Symbolic Mode
| Command | Effect |
|---|---|
chmod +x file | Add execute for all |
chmod u+x file | Add execute for owner |
chmod g+w file | Add write for group |
chmod o-r file | Remove read for others |
chmod go-w file | Remove write for group and others |
chmod a-x file | Remove execute for everyone |
chmod u=rwx,go=rx file | Set owner to rwx, group/others to rx |
chmod g+s dir/ | Set SetGID on directory |
chmod +t dir/ | Set sticky bit |
chmod u+s program | Set SetUID on executable |
Numeric Mode
| Mode | String | Typical Use |
|---|---|---|
400 | r——– | Read-only for owner only |
600 | rw——- | Private file (SSH keys, secrets) |
644 | rw-r–r– | Standard file |
664 | rw-rw-r– | Group-editable file |
700 | rwx—— | Private executable or directory |
755 | rwxr-xr-x | Standard executable or public dir |
775 | rwxrwxr-x | Group-editable directory |
777 | rwxrwxrwx | World-writable (avoid) |
1777 | rwxrwxrwt | World-writable with sticky (/tmp) |
2775 | rwxrwsr-x | SetGID collaborative directory |
4755 | rwsr-xr-x | SetUID executable |
Conclusion: chmod as Precision Instrument
chmod is deceptively simple on the surface — a command with two notation systems and a handful of flags. But used skillfully, it is a precision instrument for expressing exactly the access control policy each file and directory needs.
The key insights to carry forward: symbolic mode (chmod u+x) is cleaner for incremental changes and self-documenting scripts; numeric mode (chmod 755) is faster for setting complete permissions. Recursive chmod (-R) should almost always separate files from directories using find. Special bits (SetGID in particular) are essential for collaborative directories where files should automatically inherit group ownership. And every permission decision should be the minimum necessary — files should not be executable unless they need to be, group-writable unless sharing requires it, world-accessible unless public access is the intent.
With chmod and the permission system fully understood, you have genuine control over who can do what with every file on your Linux system — and the tools to enforce that control precisely and deliberately.








