Linux permissions: chmod, chown and umask made clear

updated 2026-07-01#linux#permissions#chmod#chown

Reading ls -l

shell
ls -l script.sh
-rwxr-xr-- 1 alice devs 4096 Jul  1 10:00 script.sh

Break -rwxr-xr-- into 1 + 3 + 3 + 3 characters:

  • - : the type — - file, d directory, l symlink.
  • rwx : the owner (alice) can read, write, execute.
  • r-x : the group (devs) can read and execute, not write.
  • r-- : others can only read.

Three blocks, always in the same order: user, group, others. r = read, w = write, x = execute (for a directory, x means the right to enter it).

Octal notation

Each right has a value: r = 4, w = 2, x = 1. Add them up per block: rwx = 7, r-x = 5, r-- = 4. Hence the classics:

  • 755 (rwxr-xr-x): scripts and directories — the owner does everything, others read and traverse.
  • 644 (rw-r--r--): regular files — the owner edits, others read.
  • 600 (rw-------): secrets (SSH keys, .env) — nobody but you.

chmod: changing rights

shell
chmod 644 notes.txt        # octal : fixe tout d'un coup / octal: set everything at once
chmod u+x deploy.sh        # symbolique : ajoute x au propriétaire / symbolic: add x for the owner
chmod g-w,o-r config.yml   # retire w au groupe, r aux autres / remove w from group, r from others
chmod -R 755 /var/www/site # récursif sur un dossier / recursive on a directory

Two syntaxes, same result. Octal (chmod 644) replaces all permissions at once — ideal when you know the final state you want. Symbolic (u+x, g-w) only changes what you name: u/g/o/a for user/group/others/all, +/-/= to add/remove/set.

chown and chgrp: changing ownership

shell
sudo chown alice fichier.txt        # change le propriétaire / change the owner
sudo chown alice:devs fichier.txt   # propriétaire ET groupe / owner AND group
sudo chgrp devs fichier.txt         # groupe seulement / group only
sudo chown -R alice:devs /srv/app   # récursif / recursive

chmod sets which rights; chown sets who they apply to. Changing the owner requires sudo (you can't "give away" a file). The user:group form does both in one command.

The classic Docker "Permission denied"

Your container crashes with Permission denied on its mounted volume? It's almost always a UID mismatch: Linux doesn't compare usernames, it compares numbers. If the container process runs as UID 1000 but the host directory belongs to root (UID 0), the container can't write — names don't matter.

The fix: hand the host directory to the UID the container uses (stated in the image docs, or visible with docker exec <ctn> id).

shell
docker exec mon-conteneur id       # → uid=1000 gid=1000
sudo chown -R 1000:1000 ./app-data # aligne le dossier hôte sur l'UID du conteneur
                                   # align the host dir with the container UID

umask in two sentences

umask defines the permissions removed by default from every file you create: with the common umask 022, a file is born as 644 (666 − 022) and a directory as 755 (777 − 022). That's why your new files are never executable or group-writable unless you ask.

⚠️ Don't chmod -R 777

chmod -R 777 "fixes" the error by giving every right to everyone — including any compromised process on the machine. It's a band-aid that hides the real problem (wrong ownership) and leaves a lasting hole.

Instead: identify who needs access (ls -l, id, docker exec ... id), then fix ownership with chown and keep rights minimal (755/644, 600 for secrets). If several users must write, create a shared group rather than opening up to everyone.