October 4, 2026 · Yunus Emre Vurgun

How Do Linux File Permissions and Chmod Work?

cli · tutorial · reference · auth

Every file and directory on Linux carries nine permission bits: read, write, and execute for the owner, the group, and everyone else. The chmod command sets these bits, either as an octal number like 755 or as symbols like u+x. This guide explains how to read the permission string, how both chmod notations work, and which settings are safe for common situations.

Reading the permission string

Run ls -l and each line starts with ten characters, for example -rwxr-xr--. The first character is the file type (- for a regular file, d for a directory, l for a symlink), and the remaining nine are three triplets: owner, group, and others. Each triplet holds read (r), write (w), and execute (x) slots, with a dash where a permission is absent.

StringOwnerGroupOthersMeaning
-rwxr-xr-xrwxr-xr-xOwner can do everything; rest can read and run
-rw-r--r--rw-r--r--Owner can edit; rest can only read
-rw-------rw-------Only the owner can read or write
drwxr-x---rwxr-x---Directory open to owner and group only
-rwsr-xr-xrwsr-xr-xSetuid bit set; runs with owner privileges

Permissions mean something different on directories than on files. Read on a directory lets you list its names, write lets you create, rename, and delete entries inside it, and execute lets you traverse into it and access files you know by name. A directory with read but no execute is a classic trap: you can see filenames but cannot open any of them. The file systems catalog entry explains how these bits fit into inode metadata.

Octal notation: why 755 and 644

Each triplet maps to one octal digit by adding read=4, write=2, and execute=1. So rwx is 7, r-x is 5, r-- is 4, and --- is 0. Three digits cover owner, group, and others in order, which is why chmod 755 script.sh produces rwxr-xr-x and chmod 644 notes.txt produces rw-r--r--.

OctalStringTypical use
777rwxrwxrwxWorld-writable; almost never what you want
755rwxr-xr-xExecutable scripts and public directories
750rwxr-x---Scripts shared with one group only
700rwx------Private scripts and SSH directories
644rw-r--r--Regular files anyone may read
640rw-r-----Files readable by owner and group only
600rw-------Private keys and secret config files
400r--------Read-only secrets, nothing may modify

A leading fourth digit sets the special bits: setuid (4), setgid (2), and the sticky bit (1). chmod 4755 adds setuid so the program runs as its owner, chmod 2750 makes new files in a directory inherit its group, and chmod 1777 on /tmp lets anyone create files but only delete their own. Memorize 755, 644, and 600 first; they cover the vast majority of daily work.

Symbolic notation for precise changes

Symbolic mode changes one thing without touching the rest, using the form who-operator-permission. The who is u (owner), g (group), o (others), or a (all); the operator is + to add, - to remove, or = to set exactly; and the permission is any mix of r, w, x, plus X for execute-only-on-directories.

chmod u+x deploy.sh        # make executable for the owner only
chmod go-w report.txt      # remove group and other write access
chmod a-x secret.key       # nobody may execute this file
chmod u=rw,go=r config.yml # exactly rw for owner, read for rest
chmod -R a+rX docs/        # readable tree, executables stay sane

The capital X deserves attention: it adds execute only to directories and to files that already have some execute bit. That makes chmod -R a+rX the safe way to fix a copied tree without accidentally marking every text file executable. Symbolic mode also shines in scripts where the starting state is unknown, since u+x cannot strip group permissions the way a bare 755 might. These operations pair with moving and copying files — see the Unix file commands cheat sheet and the file operations catalog entry.

Ownership, groups, and the directory trap

Permissions answer who, but ownership answers who the who is. chown user:group file sets both at once, and chgrp group file changes just the group. A web server running as www-data cannot write an uploads folder owned by your account until you either change the group or widen the other bits — and changing the group is the safer of the two.

chown deploy:deploy app/ -R    # give the tree to the deploy user
chown :www-data uploads/      # set group only, keep the owner
chmod 775 uploads/             # owner and group can write
ls -ld uploads/               # verify with the directory flag

New files inherit their group from the creating process by default, which breaks shared folders when collaborators have different primary groups. Setting the setgid bit on the directory (chmod g+s shared/) makes new files inherit the directory group instead, and combining that with a umask of 002 keeps group writes working. This two-step setup — setgid plus umask — is the standard recipe for any directory two people must write to.

Why do I get permission denied even though the file is readable?

Because opening a file requires execute permission on every directory above it. A file with mode 644 is still unreachable if its parent directory is 700 and owned by someone else — the kernel blocks traversal before it ever checks the file. Diagnose from the top down with namei -l /path/to/file, which prints each path component with its owner and mode on one screen. Other frequent causes are the file living on a read-only or root-squashed network mount, an SELinux or AppArmor policy denying the access despite the bits, and scripts lacking the execute bit being run as ./script.sh instead of bash script.sh. Fix the actual layer: traversal bits, mount options, or the MAC policy — never paper over it with 777.

Sane defaults and what never to chmod 777

Start from restrictive and open up deliberately. Home directories are typically 750 or 700, project files 644, scripts 755, SSH keys 600, and the .ssh directory itself 700 — OpenSSH refuses to use keys that are group- or world-accessible, which is the single most common permission error developers hit. Web roots usually work as 755 directories with 644 files, with only upload and cache folders writable by the server user. Never 777 anything containing code or secrets: on a shared host it lets every other account read and modify your files, and on a web server it can turn an upload form into remote code execution. When something breaks, find the denied layer with namei and grant the minimum that fixes it.