chmod

Change file and directory permissions

Updated 2026-08-12

chmod changes who can read, write, or execute a file or directory. It never changes who the owner and the group are, which is chown's job. Every file has three permission classes (owner, group, and everyone else), and chmod sets them either as a three-digit numeric mode (chmod 644 file) or as a targeted symbolic edit (chmod u+x file). For the full owner/group/other model, what each bit means on a directory, and how umask fits in, see File permissions explained.

Numeric mode replaces all nine bits

Numeric mode is one octal digit per class (owner, group, other), where r=4, w=2, and x=1 sum together: chmod 755 script.sh gives the owner rwx (7) and group/other r-x (5) each. It's fast once the arithmetic is automatic, but it always sets all nine bits in one go, discarding whatever combination was there before.

Symbolic mode changes one and leaves the rest

Symbolic mode names a class (u, g, o, or a), an operator (+, -, =), and a permission letter: chmod u+x script.sh adds execute for the owner only, without touching anything else. Use symbolic mode when you want to flip one bit rather than recompute the whole three-digit number from scratch.

Recursive changes need care

chmod -R applies a mode to a directory and everything inside it, files and subdirectories alike, in one pass. That includes anything whose permissions were deliberately tighter than the rest of the tree (a private key sitting inside a project directory, say), and there's no built-in undo once it's done. The examples below show a type-aware alternative, using find, before the blunt -R version and the failure mode it produces.

Permissions aren't the only gate

A permission-denied error doesn't always mean the file's own mode is wrong. Reading, writing, or deleting a file also depends on the permissions of every directory between it and the filesystem root, and deleting a file is governed by the directory's write permission, not the file's. The troubleshooting section below walks through both.

Sample files used on this page

Every example below was run against these files. Recreate them to follow along.

./ the modes every example starts from - ls -l, before any of them run

total 28
-rw-r--r-- 1 user user    0 Aug 12 21:45 a.txt
-rw-r--r-- 1 user user    0 Aug 12 21:45 b.txt
-rw-r--r-- 1 user user   18 Aug 12 21:45 backup.sh
---------- 1 user user    0 Aug 12 21:45 blank.txt
-rw-r--r-- 1 user user    0 Aug 12 21:45 c.txt
drwxr-xr-x 2 user user 4096 Aug 12 21:45 data
-rwxr--r-- 1 user user   20 Aug 12 21:45 deploy.sh
-rw------- 1 user user    0 Aug 12 21:45 id_rsa
drw------- 2 user user 4096 Aug 12 21:45 locked
lrwxrwxrwx 1 user user    9 Aug 12 21:45 notes-link -> notes.txt
-rw-r--r-- 1 user user    0 Aug 12 21:45 notes.txt
drwxr-xr-x 5 user user 4096 Aug 12 21:45 project
-rw-r--r-- 1 user user    0 Aug 12 21:45 report.csv
drwxr-xr-x 2 user user 4096 Aug 12 21:45 shared
-rwxr-xr-x 1 user user   20 Aug 12 21:45 tool

project/ the tree the recursive and auditing examples walk - oops.txt is the world-writable one

project:
total 12
drwxr-xr-x 2 user user 4096 Aug 12 21:45 data
-rw-r--r-- 1 user user    0 Aug 12 21:45 notes.txt
-rw-rw-rw- 1 user user    0 Aug 12 21:45 oops.txt
drwxr-xr-x 2 user user 4096 Aug 12 21:45 scripts
drwxr-xr-x 2 user user 4096 Aug 12 21:45 secrets

project/data:
total 0
-rw-r--r-- 1 user user 0 Aug 12 21:45 report.csv

project/scripts:
total 4
-rw-r--r-- 1 user user 20 Aug 12 21:45 deploy.sh

project/secrets:
total 0
-rw------- 1 user user 0 Aug 12 21:45 id_rsa
43 outputs, collapsed by default

Reading and setting basic permissions

Numeric mode for the common case, symbolic mode for a single-bit tweak.

Set a file to the standard rw-r--r-- mode

chmod 644 notes.txt && ls -l notes.txt

The most common numeric mode: the owner can read and write, everyone else can only read.

Show output
-rw-r--r-- 1 user user 0 Aug 12 21:45 notes.txt

Add execute permission for the owner only

chmod u+x deploy.sh && ls -l deploy.sh

u targets the owner, +x adds execute without touching read, write, or the group/other bits.

Show output
-rwxr--r-- 1 user user 20 Aug 12 21:45 deploy.sh

Remove write permission from group and other

chmod go-w notes.txt && ls -l notes.txt

Combine two classes (g and o) in one operator. Owner permissions are untouched.

Show output
-rw-r--r-- 1 user user 0 Aug 12 21:45 notes.txt

Add read permission for everyone

chmod a+r notes.txt && ls -l notes.txt

a means all three classes at once: owner, group, and other.

Show output
-rw-r--r-- 1 user user 0 Aug 12 21:45 notes.txt

Set an exact permission set with symbolic mode

chmod u=rwx,g=rx,o=r deploy.sh && ls -l deploy.sh

= assigns exactly the listed permissions to a class, clearing any others it had. Comma-separate multiple class assignments in a single command.

Show output
-rwxr-xr-- 1 user user 20 Aug 12 21:45 deploy.sh

Check a file's current mode as a number

stat --format '%a %n' deploy.sh

stat prints the numeric mode directly, handy for scripts that need to compare or restore permissions rather than parse ls -l.

Show output
744 deploy.sh

Common permission recipes

The handful of numeric modes that cover most real files.

Make a script executable

chmod 755 deploy.sh && ls -l deploy.sh

rwxr-xr-x: the owner can edit and run it, everyone else can only run it. The standard mode for scripts and compiled binaries.

Show output
-rwxr-xr-x 1 user user 20 Aug 12 21:45 deploy.sh

Set a plain data file to the standard mode

chmod 644 report.csv && ls -l report.csv

rw-r--r--: the owner can edit it, everyone else can read it. What most new files should end up at.

Show output
-rw-r--r-- 1 user user 0 Aug 12 21:45 report.csv

Lock a private key down to owner-only

chmod 600 id_rsa && ls -l id_rsa

rw-------: only the owner can read or write it, nobody else can even list its contents. SSH refuses to use a private key with looser permissions than this.

Show output
-rw------- 1 user user 0 Aug 12 21:45 id_rsa

Lock a directory down to owner-only

chmod 700 data/ && ls -ld data

rwx------: only the owner can list, enter, or modify this directory at all.

Show output
drwx------ 2 user user 4096 Aug 12 21:45 data

Make a file group-writable for shared editing

chmod 664 notes.txt && ls -l notes.txt

rw-rw-r--: owner and group can both edit it, other can only read. Useful in a shared project directory with a common group.

Show output
-rw-rw-r-- 1 user user 0 Aug 12 21:45 notes.txt

Restrict a directory to owner-write, group-browse

chmod 750 data/ && ls -ld data

rwxr-x---: owner has full control, group can look inside and read files, other has nothing. A common mode for a team's working directory.

Show output
drwxr-x--- 2 user user 4096 Aug 12 21:45 data

A leading zero is the same as no leading zero

chmod 0644 notes.txt && ls -l notes.txt

The fourth (special-bits) digit defaults to 0, so 0644 and 644 do the same thing. You'll see the four-digit form in scripts that also set setuid/setgid/sticky.

Show output
-rw-r--r-- 1 user user 0 Aug 12 21:45 notes.txt

Symbolic operators: +, -, and =

Add, remove, or set exactly, per class, without recomputing the whole number.

Add execute for all classes with the +x shorthand

chmod +x deploy.sh && ls -l deploy.sh

With no class letter given, chmod acts on all three classes, the same as a+x, but honours the current umask on new bits.

Show output
-rwxr-xr-x 1 user user 20 Aug 12 21:45 deploy.sh

Add a permission to more than one class at once

chmod u+x,g+x deploy.sh && ls -l deploy.sh

Comma-separate multiple class-operator pairs to change several classes differently in one command.

Show output
-rwxr-xr-- 1 user user 20 Aug 12 21:45 deploy.sh

Strip every permission from other

chmod o-rwx notes.txt && ls -l notes.txt

o-rwx removes read, write, and execute for other in one go, without needing to know what other currently had.

Show output
-rw-r----- 1 user user 0 Aug 12 21:45 notes.txt

Copy the owner's permissions onto the group

chmod g=u notes.txt && ls -l notes.txt

g=u sets the group's bits to match whatever the owner currently has, instead of listing them out by hand.

Show output
-rw-rw-r-- 1 user user 0 Aug 12 21:45 notes.txt

Remove execute from every class

chmod a-x deploy.sh && ls -l deploy.sh

Turns an executable back into a plain file without affecting its read or write bits.

Show output
-rw-r--r-- 1 user user 20 Aug 12 21:45 deploy.sh

Add read, write, and conditional execute in one operator

chmod u+rwX blank.txt && ls -l blank.txt

Capital X (unlike lowercase x) only adds execute if the file already has execute set for someone, or if it's a directory. On a plain non-executable file like this one, the X has no effect; only rw gets added.

Show output
-rw------- 1 user user 0 Aug 12 21:45 blank.txt

= without a class still respects the umask

chmod =rwx notes.txt && ls -l notes.txt

=rwx with no class letter defaults to all classes, like a=rwx, but unlike an explicit a=rwx it's filtered through the current umask (0022 here), so group and other lose the write bit that a bare 777 would have kept.

Show output
-rwxr-xr-x 1 user user 0 Aug 12 21:45 notes.txt

Changing several files at once

A single command can carry as many targets as you give it.

Set the same mode on a list of files

chmod 600 a.txt b.txt c.txt && ls -l a.txt b.txt c.txt

chmod accepts any number of targets after the mode; each gets the same change.

Show output
-rw------- 1 user user 0 Aug 12 21:45 a.txt
-rw------- 1 user user 0 Aug 12 21:45 b.txt
-rw------- 1 user user 0 Aug 12 21:45 c.txt

Set the same mode on every file matching a glob

chmod 644 *.txt && ls -l a.txt b.txt c.txt notes.txt

The shell expands *.txt before chmod ever runs, so this touches every matching file in the current directory, not just the ones you're thinking of. Check with ls *.txt first if you're unsure what will match.

Show output
-rw-r--r-- 1 user user 0 Aug 12 21:45 a.txt
-rw-r--r-- 1 user user 0 Aug 12 21:45 b.txt
-rw-r--r-- 1 user user 0 Aug 12 21:45 c.txt
-rw-r--r-- 1 user user 0 Aug 12 21:45 notes.txt

Changing permissions recursively

-R walks a whole directory tree in one pass. Prefer a type-aware approach, since files and directories usually need different modes and a blanket -R can't tell the difference.

Make only scripts executable, by name pattern

find project -type f -name "*.sh" -exec chmod +x {} \; && ls -l project/scripts/deploy.sh

Restrict the -exec further with -name so only matching files get the execute bit, leaving other file types at their existing mode.

Show output
-rwxr-xr-x 1 user user 20 Aug 12 21:45 project/scripts/deploy.sh

Pipe find into xargs for the same effect

find project -type f -name "*.txt" -print0 | xargs -0 chmod 644

-print0 and xargs -0 handle filenames with spaces or newlines safely, and batch many files into fewer chmod invocations than repeated -exec ... {} \; calls.

Add a permission recursively without resetting anything else

chmod -R u+w project/

Because +w only adds a bit, it can't remove permissions that were already tighter elsewhere in the tree, unlike a numeric -R reset. Safer when the goal is "make sure I can write to all of this" rather than "set an exact mode everywhere."

Add execute recursively, but only where it already makes sense

chmod -R a+X project/

Capital X adds execute to directories (so they stay traversable) and to files that are already executable for someone, but leaves plain data files alone. Safer than a+x for a mixed tree, since it won't make every text file "executable."

Refuse to recurse over / by accident

chmod -R --preserve-root 755 /

--preserve-root is the default in current GNU coreutils, but making it explicit documents intent in a script. It fails fast, before touching anything, if the target resolves to /.

Show output
chmod: it is dangerous to operate recursively on '/'
chmod: use --no-preserve-root to override this failsafe

Reset an entire tree to one mode (the blunt, risky version)

chmod -R 755 project/ && ls -ld project project/data project/data/report.csv project/secrets/id_rsa

Danger: a numeric -R sets every matching file and directory to exactly this mode, overwriting anything tighter that was there on purpose. Run this on a tree containing a 600 private key or a 700 secrets directory and it silently makes them world-readable and world-executable, with no prompt and no way back except restoring from a backup or re-applying the original permissions by hand. Prefer the type-aware find commands above.

Show output
drwxr-xr-x 5 user user 4096 Aug 12 21:45 project
drwxr-xr-x 2 user user 4096 Aug 12 21:45 project/data
-rwxr-xr-x 1 user user    0 Aug 12 21:45 project/data/report.csv
-rwxr-xr-x 1 user user    0 Aug 12 21:45 project/secrets/id_rsa

Special permission bits: setuid, setgid, sticky

Above the normal nine bits sit three more, with a numeric digit of their own (4000/2000/1000).

Make new files in a directory inherit its group

chmod g+s shared/ && ls -ld shared

Setgid on a directory makes files created inside it take the directory's group, instead of the creating user's primary group. Shows as an s in the group execute slot.

Show output
drwxr-sr-x 2 user user 4096 Aug 12 21:45 shared

Set setgid and full group access in one numeric mode

chmod 2775 shared/ && ls -ld shared

The leading 2 sets setgid; 775 gives owner and group full access and other read/execute. A common mode for a shared team directory.

Show output
drwxrwsr-x 2 user user 4096 Aug 12 21:45 shared

Set setuid on an executable

chmod 4755 tool && ls -l tool

The leading 4 sets setuid, shown as s in the owner execute slot: the program runs with the file owner's privileges rather than the caller's. Note this only takes effect on compiled binaries: the Linux kernel deliberately ignores the setuid bit on #!-scripts for security reasons, even though chmod still applies it to the file.

Show output
-rwsr-xr-x 1 user user 20 Aug 12 21:45 tool

Remove setuid and setgid

chmod u-s,g-s tool

Clears both special bits with symbolic mode, without needing to know or recompute the rest of the numeric mode.

Set the sticky bit on a shared directory

chmod +t shared/ && ls -ld shared

Sticky, shown as t in the other execute slot, restricts deleting or renaming a file inside the directory to that file's own owner (or root), even when others have write access to the directory itself. This is how /tmp stays shared but not a free-for-all.

Show output
drwxr-xr-t 2 user user 4096 Aug 12 21:45 shared

Symlinks themselves have no meaningful permissions on Linux; chmod follows them by default.

Copying and reporting permission changes

Reuse a known-good mode, or see exactly what changed.

Copy one file's permissions onto another

chmod --reference=deploy.sh notes.txt && ls -l notes.txt

Sets notes.txt to whatever mode deploy.sh currently has, instead of spelling the mode out. Useful in scripts that need to match an existing file's permissions exactly.

Show output
-rwxr--r-- 1 user user 0 Aug 12 21:45 notes.txt

Only print a line when the mode actually changes

chmod -c 755 notes.txt

-c (--changes) stays silent if the file was already at the target mode, and reports it like -v only when something changed.

Show output
mode of 'notes.txt' changed from 0644 (rw-r--r--) to 0755 (rwxr-xr-x)

Always report the mode, changed or not

chmod -v 644 notes.txt

-v (--verbose) prints a line for every target, even ones already at the requested mode, useful when auditing a batch change ran over everything you expected.

Show output
mode of 'notes.txt' retained as 0644 (rw-r--r--)

Auditing permissions across a tree

find's -perm test locates files by mode, a natural pairing with chmod.

Find world-writable files, a common security smell

find project -type f -perm -002

-perm -002 matches files where the other-write bit is set, regardless of the rest of the mode. Worth running before trusting a tree pulled from somewhere else.

Show output
project/oops.txt

Find setuid binaries on the system

find /usr/bin -maxdepth 1 -perm -4000 | sort

-perm -4000 matches the setuid bit specifically. A short, expected list on a stock Debian install (su, passwd, and a handful of others); an unfamiliar entry here is worth investigating.

Show output

Your output will differ: which binaries are setuid depends on what you have installed; this is a minimal Debian plus sudo

/usr/bin/chfn
/usr/bin/chsh
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/su
/usr/bin/sudo
/usr/bin/umount

Troubleshooting permission errors

What chmod itself reports, and what looks like a chmod problem but isn't.

chmod on a file that doesn't exist

chmod 644 does-not-exist.txt

A plain, specific error rather than a silent no-op. Check the path and spelling before assuming permissions are the problem.

Show output
chmod: cannot access 'does-not-exist.txt': No such file or directory

chmod on a file you don't own

chmod 600 /etc/shadow

Only the file's owner (or root) can change its mode. Everyone else gets Operation not permitted, no matter what permissions the file currently has.

Show output
chmod: changing permissions of '/etc/shadow': Operation not permitted

Running a script without the execute bit

./backup.sh

Read permission is enough to view a script's contents, but execute permission is required to run it directly. chmod +x is the fix, not a syntax problem in the script.

Show output
bash: ./backup.sh: Permission denied

Deleting a file depends on the directory's permissions, not the file's

chmod 000 data/locked.txt
rm -f data/locked.txt

A file with no permissions at all can still be deleted, because removing a directory entry is controlled by the directory's write bit, not the target file's mode. Locking a file down to 000 does not protect it from deletion by anyone who can write to its parent directory. rm has the same rule from the other side, including what the sticky bit on /tmp is there to fix.

chmod changes existing files; umask governs new ones

umask
touch fresh.txt
stat -c '%A %n' fresh.txt

chmod never runs automatically. Every new file lands at a mode set by umask subtracted from a default, which is why plain files consistently appear at 644 without anyone typing chmod. See File permissions explained for how the subtraction works.

Show output
0022
-rw-r--r-- fresh.txt