Linux file permissions: chmod, chown and umask explained

Read rwxr-xr-x at a glance, set it with chmod and chown, and fix the classic permission mistakes.

Part 5 of 12 in Linux basics for self-hosters. Last updated

In short: Every file has an owner, a group and three sets of rights (read, write, execute) for the owner, the group and everyone else. chmod 644 file gives the owner read and write and everyone else read; chmod 755 adds execute, which scripts and directories need. chown alice:media file changes the owner and group. Never fix a permission error with chmod 777; find out which user needs access and give exactly that user or group the right.

Reading ls -l

ls -l shows the permissions in the first column:

-rw-r--r-- 1 alice alice   220 Sep 27 10:12 notes.txt
-rwxr-xr-x 1 alice alice  1408 Sep 27 10:15 backup.sh
drwxr-x--- 2 alice media  4096 Sep 27 10:20 photos

Split the first ten characters into four parts:

How to read drwxr-x---
PartExampleMeaning
Typed- file, d directory, l symbolic link
OwnerrwxThe user in column 3 (alice) may read, write and execute
Groupr-xMembers of the group in column 4 (media) may read and enter
Others---Everyone else gets nothing

On a file, r reads the content, w changes it and x runs it. On a directory, r lists the names, w creates and deletes files in it, and x lets you enter it at all. Deleting a file is a right on the directory, not on the file. stat -c '%a %A %U:%G' file prints the octal mode, the symbolic mode and the owner in one line.

chmod: octal and symbolic

Octal sets all three classes at once. Add up read (4), write (2) and execute (1) per class: 6 is read and write, 5 is read and execute, 7 is everything.

rwxr-x--- is 750: add 4, 2 and 1 for each letter that is set.
The modes you will use most
ModeSymbolicTypical use
644rw-r--r--Normal files, config files that are not secret
600rw-------Secrets: private keys, credential files
755rwxr-xr-xScripts, programs and ordinary directories
750rwxr-x---Directories shared with one group only
700rwx------Private directories such as ~/.ssh

Symbolic changes only what you name: u (user, the owner), g (group), o (others), a (all), with +, - or =. Separate several changes with a comma and no space:

chmod 600 ~/.config/rclone/rclone.conf   # owner only
chmod u+x backup.sh                      # add execute for the owner
chmod g+w,o-rwx shared.txt               # group may write, others get nothing
chmod u=rwx,go=r script.sh               # exactly rwxr--r--
chmod -R u+rwX,go-rwx ~/private          # capital X: execute only on directories

The chmod calculator converts between the two forms and explains every bit. The reference is chmod(1).

chown and groups

Only root may give a file to another user, so chown usually needs sudo. The form is user:group; leave out either side to keep it.

sudo chown alice notes.txt              # new owner, group unchanged
sudo chown alice:media /srv/media       # owner and group
sudo chown :media /srv/media/film.mkv   # group only (same as chgrp media)
sudo chown -R alice:media /srv/media    # the whole tree

Groups are how you share without opening things to everyone: put the users that need access in one group, give the directory to that group, and set 750 or 770. Adding users to groups is covered in users, groups and sudo.

umask: the default for new files

New files start at 666 and new directories at 777, minus the bits in your umask. The common default umask 022 removes write for group and others, so new files are 644 and new directories 755. Run umask to see yours.

umask            # 0022
umask 027        # this shell only: new files 640, new directories 750
touch a.txt; mkdir d; stat -c '%a %n' a.txt d
# 640 a.txt
# 750 d

The same with the default umask, then chmod in both notations, run in an empty directory:

$ umask; touch notes.txt; mkdir share; ls -ld notes.txt share
0022
-rw-r--r-- 1 user user 0 Sep 28 06:29 notes.txt
drwxr-xr-x 1 user user 0 Sep 28 06:29 share

$ chmod 640 notes.txt; chmod u=rwx,g=rx,o= share; stat -c '%A  %a  %n' notes.txt share
-rw-r-----  640  notes.txt
drwxr-x---  750  share

Real output on openSUSE Tumbleweed, 2026-09-28; user and host names and addresses redacted.

For a systemd service, set UMask=0027 in its unit instead of changing the shell.

setgid and the sticky bit

  • setgid on a directory (chmod g+s dir, or a leading 2 as in 2775): new files inside get the directory's group instead of the creator's. Ideal for a shared /srv/media.
  • Sticky bit (chmod +t dir, a leading 1): in a directory everyone may write to, only the owner of a file may delete it. /tmp is drwxrwxrwt, which is 1777.
  • setuid (a leading 4) runs a program as its owner. It belongs to a handful of system programs such as passwd; never set it on a script.

Both on the share directory from above (mode 750). The group's x turns into s. Others have no x, so the sticky bit shows as a capital T instead of t, and the leading digit becomes 3 (2 for setgid plus 1 for sticky):

$ chmod g+s share; chmod +t share; ls -ld share; stat -c '%A %a' share
drwxr-s--T 1 user user 0 Sep 28 06:29 share
drwxr-s--T 3750

Real output on openSUSE Tumbleweed, 2026-09-28; user and host names and addresses redacted.

Permissions and rootless containers

Rootless podman maps users inside the container to other numbers outside it. Root in the container is your own user on the host; user 1000 in the container becomes a number from your range in /etc/subuid, such as 100999. That is why files in a bind-mounted directory sometimes show an owner you have never heard of.

To fix ownership from the container's point of view, run the command inside your user namespace, podman unshare chown 1000:1000 ~/appdata, or add the :U option to the volume (Volume=%h/appdata:/data:U in a quadlet) and podman chowns it for you.

Here is the mapping in action: a file handed to user 1000 inside the namespace belongs to 100999 on the host (the subuid range starts at 100000, and container UID 1 maps to 100000):

$ touch owned-by-container
$ podman unshare chown 1000:1000 owned-by-container
$ ls -ln owned-by-container
-rw-r--r-- 1 100999 100999 0 Sep 28 06:37 owned-by-container
$ podman unshare ls -ln owned-by-container
-rw-r--r-- 1 1000 1000 0 Sep 28 06:37 owned-by-container

Real output on openSUSE Tumbleweed, podman 6.0.2, 2026-09-28; user and host names and addresses redacted.

Common mistakes

Fixing "Permission denied" with chmod 777

777 lets every user and every compromised service on the machine change or replace the file. Find out which user runs the program (ps -o user= -p PID or the User= of the unit), then give that user or its group the one right it lacks.

chmod -R 755 on a whole tree

It marks every photo and text file as executable. Use capital X (chmod -R u=rwX,go=rX dir) or set directories and files separately: find dir -type d -exec chmod 755 {} + and find dir -type f -exec chmod 644 {} +.

chmod: invalid mode: 'u=rwx,'

There is a space after the comma, as in chmod u=rwx, go=r file. chmod reads go=r as a file name. Write chmod u=rwx,go=r file.

WARNING: UNPROTECTED PRIVATE KEY FILE!

ssh refuses a private key that group or others can read. Run chmod 600 ~/.ssh/id_ed25519 and chmod 700 ~/.ssh. The shell command explainer is handy when a permission fix someone posted looks suspiciously long.

Frequently asked questions

What does chmod 755 mean?

Each digit is one class: owner, group, others. 7 is read (4) + write (2) + execute (1), 5 is read + execute. So 755 is rwxr-xr-x: the owner may do everything, the group and everyone else may read and run the file or enter the directory, but not change it.

What permissions should ~/.ssh have?

The directory 700 (drwx------), private keys and authorized_keys 600 (-rw-------), public keys 644. OpenSSH refuses to use a private key that others can read and ignores authorized_keys when the directory is writable by others.

Why does execute permission matter on a directory?

On a directory, x means you may enter it and reach the files inside, and r means you may list the names. Without x you cannot open a file in it even if the file itself is readable, so directories almost always need x wherever they have r.

How do I make a script executable?

chmod +x script.sh adds execute for everyone your umask allows, or chmod u+x script.sh for the owner only. Then run it as ./script.sh. The first line should be a shebang such as #!/usr/bin/env bash.