chmod — Manage File Permissions

Practical guide to chmod: set file permissions in octal and symbolic notation, work recursively, and avoid 777 as a security risk.

chmod (change mode) controls who may read, write and execute a file or directory – separately for the owner (u), the group (g) and everyone else (o). Day to day you reach for it to make a script executable (chmod +x), lock down a private SSH key with 600, or set web files to 644/755. You can express permissions in octal (chmod 755) or symbolically (chmod u+x): octal sets every bit absolutely, while symbolic changes individual bits precisely. For security awareness, two things matter: chmod 777 opens a file to everyone for writing and execution – it is almost never necessary and a genuine risk – and chmod -R deserves care, because it spreads permissions recursively across whole trees.

Octal Mode (Numeric)

chmod 755 <file> — Owner: rwx, Group: r-x, Others: r-x. Standard for executable files and directories.

chmod 755 script.sh

chmod 644 <file> — Owner: rw-, Group: r--, Others: r--. Standard for regular files.

chmod 644 index.html

chmod 600 <file> — Owner: rw-, Group: ---, Others: ---. Private files, only owner can read/write.

chmod 600 ~/.ssh/id_ed25519

chmod 700 <directory> — Owner: rwx, Group: ---, Others: ---. Private directory, only owner can access.

chmod 700 ~/.ssh

chmod 664 <file> — Owner: rw-, Group: rw-, Others: r--. Shared files where group can also write.

chmod 664 shared-doc.txt

chmod 775 <directory> — Owner: rwx, Group: rwx, Others: r-x. Shared directory where group can write.

chmod 775 /var/www/shared/

chmod 400 <file> — Owner: r--, Group: ---, Others: ---. Read-only for owner, no access for anyone else.

chmod 400 secret.key

chmod 444 <file> — Owner: r--, Group: r--, Others: r--. Read-only for everyone.

chmod 444 LICENSE

chmod 000 <file> — No permissions for anyone. Only root can still access the file.

chmod 000 locked-file.txt

Octal Reference

0 = --- (no permission) — No read, write, or execute permission.

chmod 700 dir/  # Others get 0 = ---

1 = --x (execute only) — Execute permission only. For directories: can traverse but not list.

chmod 711 cgi-bin/  # Others get 1 = --x

2 = -w- (write only) — Write permission only. Rarely used alone.

chmod 722 dropbox/  # Others get 2 = -w-

4 = r-- (read only) — Read permission only.

chmod 744 script.sh  # Others get 4 = r--

5 = r-x (read + execute) — Read and execute. Standard for others on executables and directories.

chmod 755 app.bin  # Others get 5 = r-x

6 = rw- (read + write) — Read and write. Standard for owner on regular files.

chmod 644 data.txt  # Owner gets 6 = rw-

7 = rwx (read + write + execute) — Full permissions. Standard for owner on executables and directories.

chmod 755 deploy.sh  # Owner gets 7 = rwx

Symbolic Mode

chmod u+x <file> — Add execute permission for the owner (u = user/owner).

chmod u+x script.sh

chmod g+w <file> — Add write permission for the group (g = group).

chmod g+w shared.txt

chmod o-rwx <file> — Remove all permissions for others (o = others).

chmod o-rwx private.conf

chmod a+r <file> — Add read permission for all (a = all: owner + group + others).

chmod a+r README.md

chmod u+rwx,g+rx,o+rx <file> — Set multiple permissions at once using comma-separated expressions.

chmod u+rwx,g+rx,o+rx deploy.sh

chmod u=rwx,g=rx,o=rx <file> — Set exact permissions with = (replaces existing). Equivalent to 755.

chmod u=rwx,g=rx,o=rx script.sh

chmod u=rw,go=r <file> — Set owner to rw, group and others to read-only. Equivalent to 644.

chmod u=rw,go=r config.yml

chmod +x <file> — Add execute permission for all (shorthand, omitting 'a').

chmod +x install.sh

chmod -w <file> — Remove write permission for all. Makes the file read-only.

chmod -w important.conf

chmod u+s <file> — Set the setuid bit. File runs as the owner regardless of who executes it.

chmod u+s /usr/local/bin/my-tool

chmod g+s <directory> — Set the setgid bit. New files in the directory inherit the directory's group.

chmod g+s /var/www/shared/

chmod +t <directory> — Set the sticky bit. Only file owners can delete their files in this directory.

chmod +t /tmp/

Recursive & Directory Operations

chmod -R 755 <directory> — Recursively set permissions on a directory and all its contents.

chmod -R 755 /var/www/html/

chmod -R u+rwX,go+rX,go-w <directory> — Recursively set permissions. Capital X adds execute only to directories and already-executable files.

chmod -R u+rwX,go+rX,go-w /var/www/html/

find <directory> -type f -exec chmod 644 {} + — Set permissions on all files only (not directories) within a tree.

find /var/www/html/ -type f -exec chmod 644 {} +

find <directory> -type d -exec chmod 755 {} + — Set permissions on all directories only (not files) within a tree.

find /var/www/html/ -type d -exec chmod 755 {} +

find <directory> -type f -name '*.sh' -exec chmod +x {} + — Make all shell scripts executable within a directory tree.

find ./scripts/ -type f -name '*.sh' -exec chmod +x {} +

Special Bits (Octal)

chmod 4755 <file> — Set setuid (4) + owner rwx, group r-x, others r-x. File executes as owner.

chmod 4755 /usr/local/bin/my-tool

chmod 2755 <directory> — Set setgid (2) + standard directory permissions. New files inherit group.

chmod 2755 /var/www/shared/

chmod 1777 <directory> — Set sticky bit (1) + full permissions for all. Users can only delete own files.

chmod 1777 /tmp/

chmod 6755 <file> — Set both setuid (4) and setgid (2) bits. 4+2=6.

chmod 6755 /usr/local/bin/special-tool

Viewing Permissions

ls -l <file> — Show file permissions in symbolic format (e.g. -rwxr-xr-x).

ls -l script.sh

ls -la <directory> — Show permissions for all files including hidden ones.

ls -la ~/.ssh/

stat <file> — Show detailed file status including permissions in both octal and symbolic format.

stat script.sh

stat -c '%a %n' <file> — Show only the octal permissions and filename (Linux).

stat -c '%a %n' *.sh

stat -c '%A %a %n' <file> — Show symbolic permissions, octal permissions, and filename.

stat -c '%A %a %n' /var/www/html/*

namei -l <path> — Show permissions for each component along a file path. Useful for debugging access issues.

namei -l /var/www/html/index.php

Common Permission Patterns

chmod 644 <file> — Standard web files (HTML, CSS, JS, images). Owner can edit, everyone can read.

chmod 644 style.css

chmod 755 <directory> — Standard web directories. Owner full access, others can list and traverse.

chmod 755 /var/www/html/

chmod 600 <file> — SSH private keys, credentials, .env files. Only owner can read/write.

chmod 600 .env

chmod 700 <directory> — SSH directory, private config directories. Only owner can access.

chmod 700 ~/.gnupg

chmod 644 ~/.ssh/authorized_keys — SSH authorized_keys must be readable by owner and readable by sshd.

chmod 644 ~/.ssh/authorized_keys

chmod 600 ~/.ssh/config — SSH config file. Must be private to work correctly.

chmod 600 ~/.ssh/config

chmod 755 <script> — Executable scripts and binaries. Owner full access, others can read and execute.

chmod 755 deploy.sh

chmod 640 <file> — Log files and config files. Owner can read/write, group can read, others no access.

chmod 640 /etc/app/database.conf

Options & Flags

chmod -v <mode> <file> — Verbose mode. Print a message for each file processed.

chmod -v 644 *.html

chmod -c <mode> <file> — Like verbose, but only report when a change is actually made.

chmod -c 755 scripts/*.sh

chmod --reference=<ref_file> <file> — Set permissions to match those of a reference file.

chmod --reference=template.conf new.conf

chmod -R --preserve-root <mode> <directory> — Prevent accidental recursive changes to the root filesystem.

chmod -R --preserve-root 755 /var/www/

Ownership & umask

chown <user>:<group> <file> — Change the owner and group of a file.

chown www-data:www-data index.php

chown -R <user>:<group> <directory> — Recursively change owner and group for a directory tree.

chown -R www-data:www-data /var/www/html/

chgrp <group> <file> — Change only the group of a file.

chgrp developers project.conf

umask — Show the current file creation mask. Determines default permissions for new files.

umask

umask 022 — Set umask so new files get 644 and new directories get 755.

umask 022

umask 077 — Set restrictive umask. New files get 600, new directories get 700.

umask 077

Conclusion

chmod is the central tool for controlling access precisely – day to day, a handful of patterns cover most cases: 644 for files, 755 for directories and executable scripts, 600/700 for private SSH and credential data. Reach for symbolic notation (u+x, go-w) when you only want to flip individual bits, and octal when you set the state completely. From a security standpoint, two rules of thumb: almost never grant 777 – it lets anyone write and execute – and be careful with chmod -R, since it spreads permissions across entire trees; use a capital X or separate find runs to treat files and directories differently. Permissions only govern access – who owns a file is set with chown.

Further Reading

  • chown – change the owner and group of a file
  • ls – show permissions with ls -l
  • stat – show permissions in detail in octal and symbolic form