Linux file permissions decide who can read a file, change it or run it, and who can list, create or delete entries in a directory. Most permission problems on servers come down to a handful of ideas: three classes of user, three permission bits, how directories reinterpret those bits, and the default mask that shapes every new file. This guide explains each of them, shows how to read ls -l output, and covers octal and symbolic chmod modes, umask, the special bits and safe recursive changes. Use the chmod calculator alongside to convert any mode as you go.
Reading Linux file permissions in ls -l output
Run ls -l and the first column holds ten characters:
$ ls -l
-rw-r--r-- 1 deploy www-data 2048 Sep 30 09:12 index.php
drwxr-x--- 2 deploy deploy 4096 Sep 30 09:12 private
-rwxr-x--- 1 deploy deploy 512 Sep 30 09:12 deploy.sh
| Characters | Meaning | Example drwxr-x--- |
|---|---|---|
| 1 | File type: - regular file, d directory, l symbolic link | d = directory |
| 2–4 | User (owner) permissions | rwx |
| 5–7 | Group permissions | r-x |
| 8–10 | Other (everyone else) permissions | --- |
The owner and group follow the link count (deploy and www-data above). The kernel checks only one class per access: if you are the owner, the owner bits apply even when the group bits would allow more. To see the numeric mode directly, use stat -c '%a %A %n' index.php on Linux, which prints 644 -rw-r--r-- index.php; on macOS the equivalent is stat -f '%Lp %Sp %N' index.php.
What r, w and x mean for files and directories
The same three letters mean different things depending on the object:
| Bit | On a file | On a directory |
|---|---|---|
r (4) | Read the contents | List the names inside it |
w (2) | Modify the contents | Create, delete and rename entries (needs x too) |
x (1) | Run it as a program | Enter it and access entries by name |
The directory x bit is the one that trips people up. Without it you cannot cd into the directory or open any file inside it, even a file that is itself world-readable. A directory with r but no x lets you list names but not open or inspect them. It also follows that deleting a file depends on the directory's write and execute bits, not on the file's own permissions: a read-only file in a directory you can write to can still be removed.
Octal and symbolic chmod modes
An octal mode is three digits, one each for user, group and other, where each digit adds read (4), write (2) and execute (1). A symbolic mode names the class (u, g, o or a for all), an operator (+ adds, - removes, = sets exactly) and the permissions:
chmod 640 app.log # set the whole mode: rw-r-----
chmod u=rw,g=r,o= app.log # the same, symbolically
chmod g+w shared.txt # add group write, leave the rest alone
chmod o-rwx secrets.yml # remove every permission for others
chmod a+x build.sh # make executable for everyone
The practical difference is that octal always replaces the entire mode, while + and - change only the bits you name. Symbolic modes are safer when you want to adjust one permission on files that currently have different modes. Typing a mode into the chmod calculator shows both forms side by side; for 750 on a deploy script it returns:
Octal: 750
Symbolic: rwxr-x---
Owner (u): read, write, execute
Group (g): read, execute
Others (o): no access
Commands:
chmod 750 deploy.sh
chmod u=rwx,g=rx,o= deploy.sh
chmod -R 750 directory/ # recursive
Each octal digit is exactly three bits, which is why the notation fits so well. The octal to binary converter shows 7 as 111 and 5 as 101, and the octal to decimal converter explains why 755 is 493 when a program asks for the mode as a plain integer.
When to use 644, 755, 600 and 700
| Mode | Symbolic | Use it for |
|---|---|---|
| 644 | rw-r--r-- | Ordinary files that others may read: static assets, .htaccess, public config |
| 755 | rwxr-xr-x | Directories and programs that others need to enter or run |
| 600 | rw------- | Secrets: private keys, .env files, credentials |
| 700 | rwx------ | Private directories such as ~/.ssh, personal scripts |
OpenSSH checks key permissions and refuses a private key that other users can read. After creating a pair with the SSH key generator, the calculator produces the command to lock it down:
Octal: 600
Symbolic: rw-------
Owner (u): read, write
Group (g): no access
Others (o): no access
Commands:
chmod 600 ~/.ssh/id_ed25519
chmod u=rw,g=,o= ~/.ssh/id_ed25519
chmod -R 600 directory/ # recursive
For web servers, prefer giving the server's group read access (640 or 750) over opening files to everyone. If an .htaccess file built with the .htaccess redirect generator has no effect, check that Apache can read it and enter every parent directory. Avoid 777: a world-writable file or directory lets any local user or compromised process change it. Correct ownership with chown is almost always the real fix.
umask: where default permissions come from
New files start from 666 and new directories from 777, and the process umask removes bits from those values. The umask is a mask, not a subtraction: each bit set in the umask is cleared from the default.
| umask | New files | New directories | Typical setting |
|---|---|---|---|
| 022 | 644 | 755 | Common default for users |
| 002 | 664 | 775 | Shared group workflows |
| 027 | 640 | 750 | Servers and service accounts |
| 077 | 600 | 700 | Private, single-user data |
The masking matters with odd values: umask 033 gives files 644, not 633, because the execute bits it removes were never set on a new file. Run umask to see the current value (0022) or umask -S for the symbolic form (u=rwx,g=rx,o=rx). Set it in a shell profile, a systemd unit (UMask=0027) or a container entrypoint. Bind mounts in containers keep the host's modes and numeric owners, which is worth remembering when following the docker run to Compose guide.
setuid, setgid and the sticky bit
A fourth, leading octal digit holds three special bits:
- setuid (4): an executable runs with its owner's identity.
/usr/bin/passwduses it so users can update the password database. - setgid (2): on an executable it runs with the file's group; on a directory, new entries inherit the directory's group.
- sticky (1): on a directory, only the file's owner, the directory's owner or root can delete or rename a file, as on
/tmp(1777).
A shared team directory is the everyday use of setgid. The calculator output for 2775 on /srv/shared:
Octal: 2775
Symbolic: rwxrwsr-x
Owner (u): read, write, execute
Group (g): read, write, execute
Others (o): read, execute
Special: setgid
Commands:
chmod 2775 /srv/shared
chmod u=rwx,g=rwx,o=rx /srv/shared
chmod -R 2775 directory/ # recursive
The symbolic command in that output sets only the nine basic bits, so use the octal form (or add g+s) when the special bit matters.
Symbolically, set the bits with chmod g+s dir, chmod +t dir or chmod u+s file. Linux ignores setuid on interpreted scripts, and file systems mounted with nosuid ignore it entirely. From a defensive point of view, setuid-root binaries deserve regular review; list them with find / -xdev -perm -4000 -type f and remove the bit from anything that does not need it. Note that GNU chmod 755 dir keeps an existing setgid bit on a directory; clearing it numerically requires chmod 00755 dir, as described in the GNU coreutils manual.
Using chmod -R without breaking things
A recursive octal mode applies the same bits to files and directories alike, which is rarely what you want: 644 removes the x that directories need, and 755 makes every data file executable. Target each type separately with find:
find /var/www/app -type d -exec chmod 750 {} +
find /var/www/app -type f -exec chmod 640 {} +
find /var/www/app -type f ! -perm 640 -print # verify: prints nothing when done
- Double-check the path before pressing Enter; a stray space after a leading
/turns a change to one directory into a change to the whole file system. - Use
chmod -c(GNU) to print only the files whose mode actually changed. - Restore executables such as
artisanor scripts inbin/afterwards withchmod u+x.
Quick reference
Read the ten-character string as type plus three triads; remember that directories need x to be usable; reach for 644 and 755 for shared content and 600 and 700 for secrets; set a sensible umask so new files start right; treat setuid and 777 as exceptions to justify. When you need a mode quickly, the chmod calculator converts between octal, symbolic and checkboxes, including the special bits, and runs entirely in your browser.