Linux command: chmod
Sooner or later, every Linux user meets a wall of letters like -rwxr-xr-x and a piece of advice that sounds like a magic spell: "just run chmod 755 on it". The command chmod is how you change who is allowed to read, write, and run a file. Once you understand it, that wall of letters turns into a simple, readable sentence.
1. The Basics
The job of chmod is to change the mode of a file or directory. The mode is the set of permission bits that decide who may do what. Where ls only reads those permissions and shows them to you, chmod writes them.
Linux attaches three basic permissions to every file, for three separate classes of people:
| Permission | On a file | On a directory |
|---|---|---|
r (read) |
Read the contents | List the names inside |
w (write) |
Change the contents | Create, rename, or delete entries |
x (execute) |
Run it as a program | Enter it and reach files inside |
The three classes are the owner (the user who owns the file), the group (a named set of users), and others (everybody else). Three permissions times three classes is the nine letters you see in ls -l.
The command that decides who can read, write, and run. Behind three short letters sits the entire Unix permission model, an elegant octal shorthand, and a few special bits that quietly run the whole system.
This article starts with the simplest change you can make and builds up step by step to the octal notation, recursive changes, and the special bits behind commands like sudo and the shared /tmp directory. By the end, both the letters and the numbers will read like plain language.
The right mental model: a file does not "belong" to a program or a person by magic. It carries a small label that lists exactly who may read it, change it, and run it.
chmodis how you edit that label.
1.1 Reading the Permission String First
Before you change permissions, you have to read them. Run ls -l and look at the first column:
$ ls -l script.sh
-rwxr-xr-x 1 peter staff 812 Jun 1 09:14 script.sh
Those first ten characters split into four parts:
- rwx r-x r-x
| | | |
type owner group others
The first character is the file type (- for a regular file, d for a directory). The next nine are three blocks of rwx, one block per class. A letter means the permission is present; a dash means it is absent. So rwxr-xr-x reads as: the owner can read, write, and run; the group and others can read and run, but not write.
2. Where the Name Comes From
The name chmod is short for change mode.
chmod = CHange MODe
The word "mode" is the old Unix term for a file's permission bits. You will meet the same word in related places: the st_mode field in the stat system call holds exactly these bits, and the C library function that chmod calls is also named chmod(). The command is a thin wrapper around that one system call.
Like its neighbours cp (copy), mv (move), and rm (remove), the name was kept short because early Unix was typed on slow teletype terminals where every character was printed onto paper. The habit stuck, and fifty years later chmod is still chmod.
3. A Short History
The permission model that chmod edits is almost as old as Unix itself. It shipped in Unix 1st Edition at Bell Labs in 1971, and the design has barely changed since. The idea of a compact "mode" for each file, split across owner, group, and others, has outlived nearly every operating system it competed with.
| Era | Milestone |
|---|---|
| 1971 | Unix 1st Edition ships with file modes and chmod |
| 1970s | The set-user-ID bit is added, letting programs run with the owner's rights |
| 1980s | BSD adds the sticky bit behaviour used by shared directories like /tmp |
| Today | The GNU coreutils chmod runs on most Linux distributions |
As with most core commands, there are two versions in the wild. Linux systems run the GNU coreutils version; macOS and the BSDs ship a BSD version. They agree on the important things, symbolic and octal modes work the same, but a few options differ (for example, GNU spells recursive as -R and offers --reference, which BSD lacks). This article uses the GNU version, verified against coreutils 9.4, which is what you will find on almost every Linux server.
4. Simple Use Cases
4.1 Making a Script Executable
This is the single most common reason people reach for chmod. You wrote a shell script, but the system refuses to run it:
$ ./backup.sh
bash: ./backup.sh: Permission denied
The file has no execute permission yet. Add it with the +x form (short for "add execute"):
$ chmod +x backup.sh
$ ./backup.sh
Backup finished.
That is the whole fix. chmod +x turns a plain text file into a runnable command.
4.2 The Symbolic Form: Who, Operator, What
The letters you just used are part of a small, readable language. A symbolic mode has three parts:
chmod u+x file
|||
||`--- what: r (read), w (write), x (execute)
|`---- operator: + add, - remove, = set exactly
`----- who: u (user), g (group), o (others), a (all)
You read u+x as "for the user, add execute". A few everyday examples:
$ chmod u+x file # let the owner run it
$ chmod g-w file # take write away from the group
$ chmod o-r secret # hide it from everybody else
$ chmod a+r page.html # everyone may read it (a = all)
When you leave out the "who", as in the bare chmod +x from the previous example, it means "all", but limited by your umask (the default-permission mask of your shell). To avoid surprises, spell out the class you mean: chmod a+x is always unambiguous.
4.3 Changing Several Classes at Once
You can list several changes, separated by commas, in one command:
$ chmod u+rwx,go-w notes.txt # owner gets all; group and others lose write
$ ls -l notes.txt
-rwxr--r-- 1 peter staff 1234 May 28 17:02 notes.txt
The = operator is stricter than + and -: it sets a class to exactly what you name and clears the rest for that class. So chmod g=r file makes the group's permission read-only, no matter what it was before, and leaves the owner and others untouched.
5. Moderate Use Cases: The Octal Notation
Symbolic modes are readable, but experienced users often type a three-digit number instead, like chmod 755. This is octal notation, and once it clicks you will never forget it.
5.1 The Trick: Each Permission Is a Number
Give each permission a value:
| Permission | Value |
|---|---|
r read |
4 |
w write |
2 |
x execute |
1 |
To describe one class, add up the values you want. Read plus write plus execute is 4 + 2 + 1 = 7. Read plus execute is 4 + 1 = 5. Read only is 4. Because 4, 2, and 1 are powers of two, every combination adds up to a unique digit from 0 to 7, which is exactly why the system uses base 8 (octal).
5.2 Three Digits, One Per Class
A full mode is three of those digits: owner, group, others, in that order.
chmod 7 5 5 file
| | |
| | +--- others: 4+1 = r-x
| +----- group: 4+1 = r-x
+------- owner: 4+2+1 = rwx
So 755 is rwxr-xr-x. Here are the numbers you will use most:
| Octal | Symbolic | Typical use |
|---|---|---|
644 |
rw-r--r-- |
A normal file: owner edits, everyone reads |
755 |
rwxr-xr-x |
A script or a directory: everyone may run or enter |
600 |
rw------- |
A private file, for example an SSH key |
700 |
rwx------ |
A private directory only the owner may enter |
664 |
rw-rw-r-- |
A file a whole group may edit together |
You can check any change straight away with ls -l, or ask chmod itself to report what it did with -c (short for changes):
$ chmod -c 640 report.txt
mode of 'report.txt' changed from 0644 (rw-r--r--) to 0640 (rw-r-----)
5.3 Symbolic or Octal: Which to Use?
They do the same job; the difference is intent. Octal sets the whole mode at once and is best when you know exactly what you want (chmod 644 file). Symbolic adjusts one thing and leaves the rest alone (chmod +x file adds execute without touching read or write). Reach for symbolic when you mean "add this" or "remove that", and octal when you mean "make it exactly this".
5.4 Where a File's First Permissions Come From: umask
If you never run chmod, a new file still gets some mode. Where does it come from? Every shell carries a umask (short for user mask), a set of bits it removes from the permissions of anything you create.
New files start from 666 (rw-rw-rw-) and new directories from 777 (rwxrwxrwx). Note that files never start with execute; that is why a fresh script needs chmod +x. The umask then clears whatever bits it names:
$ umask
0022
$ touch a; mkdir b
$ ls -l a | cut -c1-10 # 666 with 022 cleared
-rw-r--r--
$ ls -ld b | cut -c1-10 # 777 with 022 cleared
drwxr-xr-x
A common trap is to describe this as subtraction, as in "666 minus 022 is 644". That happens to give the right answer for tidy values, but it is not how it works. The umask turns bits off; it never turns them on. With umask 023, a file becomes 644, not 643, because masking cannot clear a bit that was never set (files have no execute bit to remove in the "others" slot). Think "which bits does the mask take away", not "subtract the numbers".
Back to top
chmodsets the permissions of a file that already exists;umasksets the permissions of files that do not exist yet. Together they answer "who can touch this?" from creation to deletion.
6. Advanced Use Cases
6.1 Changing a Whole Tree: -R
The -R flag (short for recursive) applies the mode to a directory and everything inside it:
$ chmod -R 755 /var/www/site
This is powerful and, used carelessly, harmful. The trap is that files and directories need different permissions. A directory needs execute (x) so you can enter it, but a plain data file usually should not be executable. Running chmod -R 755 makes every file executable, and chmod -R 644 strips the execute bit off every directory, which then locks you out of them.
6.2 The Capital X: Execute Only Where It Makes Sense
GNU chmod solves that trap with a special permission letter, capital X. It adds execute only to directories and to files that already have at least one execute bit. Plain data files are left alone.
$ chmod -R u=rwX,go=rX /var/www/site
Read that as: give the owner read and write everywhere, plus execute only where it belongs; give the group and others read, plus execute only where it belongs. This one command sets a sane, safe permission scheme across an entire website in a single pass. A quick demonstration of the difference:
$ ls -l
-rw-rw-r-- 1 peter staff 0 ... plain.txt # a data file, no execute
drwx------ 2 peter staff 4096 ... sub # a directory
$ chmod a+X plain.txt sub
$ ls -l
-rw-rw-r-- 1 peter staff 0 ... plain.txt # unchanged: still not executable
drwx--x--x 2 peter staff 4096 ... sub # changed: directory now enterable
6.3 Copying Permissions: --reference
Instead of naming a mode, you can tell chmod to copy the mode of another file with --reference:
$ chmod --reference=working.conf broken.conf
Now broken.conf has exactly the same permissions as working.conf. This is handy when one file in a directory behaves and another does not, and you want them to match without reading the numbers by hand.
6.4 The Special Bits: setuid, setgid, and Sticky
Beyond the nine ordinary bits there are three special bits, written as a fourth octal digit in front of the mode. They are what make parts of Linux work.
| Bit | Octal | What it does |
|---|---|---|
| setuid | 4 | On a program, run it with the owner's identity, not the caller's |
| setgid | 2 | On a program, run it as the file's group; on a directory, new files inherit that group |
| sticky | 1 | On a shared directory, only a file's owner may delete it |
The classic setuid example is passwd. An ordinary user must update the system password file, which only root may write. Setuid lets the program run as its owner, root, just for that job:
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59976 ... /usr/bin/passwd
Notice the s where the owner's x would be. That s is the setuid bit sitting on top of the execute bit. You set it by putting a 4 in front of the mode:
$ chmod 4755 myprog # rwsr-xr-x (setuid)
$ chmod 2775 shared/ # rwxrwsr-x (setgid directory)
$ chmod 1777 /tmp # rwxrwxrwt (sticky, world-writable)
The sticky bit is why /tmp works. Everyone may write there, but the trailing t means you can only delete your own files, not other people's. Without it, any user could wipe another user's temporary files.
The special bits are the quiet machinery of a multi-user system: setuid lets you change your own password, setgid keeps a shared project's files in one group, and the sticky bit stops
/tmpfrom turning into a demolition site.
One reading detail: if the execute bit underneath is missing, the letter shows as a capital S or T instead of lower case. So rwSr--r-- means setuid is set but the file is not actually executable, usually a mistake worth a second look.
7. Something Most Users Do Not Know
7.1 chmod Protects a Directory's setgid Bit
Here is a detail that surprises even seasoned administrators. You would expect a full numeric mode like chmod 755 to set the permissions to exactly that. For ordinary files it does. But on a directory, GNU chmod deliberately refuses to clear the setuid and setgid bits with a normal numeric mode:
$ ls -ld shared
drwxrwsr-x 2 peter staff 4096 ... shared # setgid is on (the 's')
$ chmod 0755 shared
$ ls -ld shared
drwxr-sr-x 2 peter staff 4096 ... shared # the 's' is STILL there
This is not a bug. The coreutils manual explains it: because set-group-ID on a directory is used to keep shared files in a common group, a plain chmod leaves those bits alone so a routine permission change does not silently break file sharing. To actually clear them, you must be explicit in one of these ways:
$ chmod g-s shared # symbolic: mention the bit directly
$ chmod =755 shared # an "operator numeric" mode
$ chmod 00755 shared # a numeric mode with five or more digits
The lesson: on directories, use symbolic g-s when you truly want the setgid bit gone. A three-digit number will not do it.
7.2 Permissions Are Enforced by the Kernel, Not chmod
It is worth knowing what chmod does and does not do. It only writes the mode bits into the file's metadata. It never checks the file, scans it, or guards it. Every time someone opens the file afterwards, the kernel reads those bits and decides yes or no. So chmod is not a lock you keep holding; it is a note you leave for the kernel to enforce, again and again, long after chmod has finished.
This also explains a famous exception: root ignores permission bits. The superuser may read and write any file regardless of its mode. Permissions protect files from ordinary users and from each other, not from root.
7.3 Knowing Where chmod Stops: ACLs and Capabilities
Part of expertise is knowing when a tool runs out. The classic mode bits describe only three classes: owner, group, and others. Two modern mechanisms go further, and it pays to recognise them when you meet them.
An Access Control List (ACL) lets you grant permissions to a specific extra user or group, beyond the three classes. You manage ACLs with setfacl and read them with getfacl:
$ setfacl -m u:john:rwx project.txt # give user john full access, on top of the mode
$ getfacl project.txt
# file: project.txt
# owner: peter
# group: staff
user::rw-
user:john:rwx
group::r--
mask::rwx
other::r--
When a file carries an ACL, ls -l adds a + at the end of the permission string, for example -rw-rwxr--+. That plus sign is your hint that chmod alone does not tell the whole story, and that you should reach for getfacl.
The second mechanism is capabilities. Instead of the all-or-nothing power of setuid-root, the kernel can grant a program one narrow privilege. That is why ping no longer needs to be setuid-root on modern systems:
$ getcap /usr/bin/ping
/usr/bin/ping cap_net_raw=ep # may open raw sockets, nothing more
You set such a privilege with setcap, for example setcap cap_net_bind_service=+ep server to let a program listen on a low port without running as root. When you audit a system and expect a setuid bit but do not find one, capabilities are often the reason.
8. Best Practices
- Prefer the least permission that works. Start restrictive.
600for private files and700for private directories are safer defaults than opening things up "just in case". - Never
chmod 777to fix a problem. It almost never is the real fix, and it lets every user on the machine change your file. If something cannot be read, the issue is usually ownership (chown) or a missing directoryxbit, not a lack of world access. - Use capital
Xfor recursive changes.chmod -R u=rwX,go=rX dirgives directories their execute bit and leaves data files non-executable, avoiding the-Rtrap. - Reach for symbolic modes to nudge, octal to set.
+xandg-wchange one thing;644and755declare the whole mode. - Remember SSH is strict. OpenSSH refuses to use a private key or
~/.sshdirectory that others can read.chmod 600 ~/.ssh/id_ed25519andchmod 700 ~/.sshare the standard fixes. - Read the manual when unsure. The habit that marks a professional is not memorising every bit; it is typing
man chmodthe moment a question comes up.
$ man chmod # the full manual page
$ chmod --help # a quick summary (GNU)
$ info coreutils 'chmod invocation' # the verbose GNU manual
Back to top9. Common Mistakes
9.1 Myth versus Reality
| Myth | Reality |
|---|---|
"chmod 777 fixes permission problems." |
It hides them and creates a security hole. The real cause is usually ownership or a missing directory x bit. |
"chmod changes who owns the file." |
No. Ownership is changed by chown. chmod only changes what each class may do. |
| "Read permission on a directory lets me open the files inside." | Reading a directory only lists names. You also need execute (x) on the directory to reach the files. |
| "Permissions keep files safe from root." | Root ignores the mode bits entirely. Permissions separate ordinary users, not the superuser. |
"chmod on a symlink changes the link." |
It follows the link and changes the target. A symlink's own mode (lrwxrwxrwx) is fixed and ignored. |
9.2 Other Traps to Avoid
- Running
chmod -R 644on a directory. This removes execute from every subdirectory and locks you out. Use capitalXinstead. - Forgetting the directory
xbit. A web server returning "403 Forbidden" often just needs execute on a parent directory, not more read access. - Confusing
644and664. One extra digit gives the whole group write access. Double-check the middle number. - Expecting
chmod 755to clear a directory's setgid bit. It will not. Usechmod g-sto remove it explicitly. - Using
chmodwhen you meanchown. If the right people still cannot reach a file after a mode change, the file probably belongs to the wrong user or group. - Assuming a
+inls -lis a typo. A trailing+such as-rw-rwxr--+means the file has an ACL. Reading only the mode bits will mislead you; check withgetfacl.
10. Summary
The chmod command is small, but it controls the entire question of "who is allowed to do what" on a Linux system.
chmodmeans "change mode". It edits the permission bits thatls -lshows, and it has been part of Unix since 1971.- Every file carries read, write, and execute permissions for three classes: owner, group, and others.
- Symbolic modes adjust one thing at a time:
u+x,g-w,a+r, and=to set exactly. - Octal modes set everything at once. Read is 4, write is 2, execute is 1; add them per class.
644,755, and600cover most daily needs. - Use
-Rto change a tree, but pair it with capitalXso data files do not all become executable. - The special bits setuid, setgid, and sticky (a fourth digit: 4, 2, 1) power tools like
passwdand the shared/tmpdirectory. - On directories, a numeric
chmodwill not clear the setgid bit; usechmod g-sfor that. - Your
umasksets the permissions of files you have not created yet; it turns bits off, so think masking, not subtraction. - When the mode bits are not enough, ACLs (
setfacl/getfacl, shown by a+inls -l) and capabilities (getcap/setcap) take over. chmodonly writes the bits. The kernel enforces them on every access, and root ignores them.- When in doubt, type
man chmod.
This is the quick reference worth keeping:
chmod +x file make a file executable
chmod u+x file add execute for the owner only
chmod g-w file remove write from the group
chmod 644 file rw-r--r-- a normal readable file
chmod 755 file rwxr-xr-x a script or directory
chmod 600 file rw------- a private file (SSH keys)
chmod 700 dir rwx------ a private directory
chmod -R u=rwX,go=rX dir safe recursive: execute only on dirs
chmod g-s dir remove the setgid bit from a directory
chmod 1777 dir rwxrwxrwt world-writable, sticky (like /tmp)
chmod --reference=A B give B the same mode as A
Permissions are one of those topics that look intimidating until the pattern clicks, and then they feel obvious. If a server of yours keeps handing out "Permission denied" or "403 Forbidden" errors, or you are not sure a setuid program should really be there, it often pays to have someone check the whole permission and ownership picture properly, before a quick chmod 777 turns a small problem into a security one.


Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.


