Permissions: User, Group, and chmod

K
Kai··5 min read

On Linux many users share one machine, so every file has permissions that decide who can read, write, and run it. Understanding this mechanism is mandatory for working on servers — and it's also the source of the "Permission denied" error everyone has hit. This article dissects it.

Reading the permission string

ls -l shows each file's permissions at the start of the line:

touch f.sh
ls -l f.sh
-rw-r--r-- 1 root root 0 May 23 09:09 f.sh

The string -rw-r--r-- has 10 characters, decoded like this:

- rw- r-- r--
│ └┬┘ └┬┘ └┬┘
│  │   │   └── other  (everyone else):     r-- = read only
│  │   └────── group  (group members):     r-- = read only
│  └────────── user   (file owner):        rw- = read + write
└───────────── type:  - file, d directory, l symlink (Article 2)
  • First character: file type (Article 2).
  • The remaining nine characters split into three groups of three: permissions for user (owner), group, and other (everyone else).
  • Each group has three permissions in a fixed order: r (read), w (write), x (execute); a - means that permission is absent.

What r, w, x mean

The meaning differs between a file and a directory — this is a common point of confusion:

For a file For a directory
r read the file's contents list the files inside (ls)
w modify the file's contents create/delete files inside
x run the file (as a program) enter the directory (cd)

Important note: for a directory, x is not "execute" but "may enter". A directory without x means you can't cd into it, even with r. And to delete a file, you need w on the directory containing it, not on the file.

Octal notation: why 755, 644...

Each permission maps to a numeric value: r = 4, w = 2, x = 1. Sum them for a number per group:

   r w x  = 4+2+1 = 7   (read, write, execute)
   r w -  = 4+2   = 6   (read, write)
   r - x  = 4+0+1 = 5   (read, execute)
   r - -  = 4     = 4   (read only)
   - - -  = 0         = 0   (no permission)

Three consecutive digits = permissions for user/group/other. So:

  • 644 = rw-r--r--: owner read/write, the rest read only. (Typical for ordinary files.)
  • 755 = rwxr-xr-x: owner full access, the rest read/execute. (Typical for directories and scripts/programs.)
  • 600 = rw-------: owner read/write only, no one else anything. (For sensitive files like SSH keys — Article 14.)

Change permissions: chmod

Two ways to write it, same result.

Octal way — set the number directly:

chmod 754 f.sh
ls -l f.sh        # -rwxr-xr--
chmod 600 f.sh
ls -l f.sh        # -rw-------

Symbolic way — add/remove permissions per group, easier to read when changing just one permission:

chmod u+x f.sh    # add x for user (u)
chmod g-w f.sh    # remove w from group (g)
chmod o=r f.sh    # set other (o) to exactly r
chmod a+r f.sh    # a = all (u+g+o), add r for everyone

Here: u user, g group, o other, a all; + add, - remove, = set exactly. Use octal to set the full permission set, symbolic to tweak one permission.

A classic situation — a script that won't run:

echo "echo hello" > run.sh
./run.sh
bash: ./run.sh: Permission denied

Because a newly created file has no x permission. Add it:

chmod +x run.sh
./run.sh          # hello

This is why you always chmod +x a script before running it (Article 16).

Change ownership: chown

chown changes the user/group that owns a file (usually needs root — Article 12):

chown alice file.txt          # change owner to alice
chown alice:dev file.txt      # change owner to alice, group to dev
chown -R alice:dev /var/app   # -R: recursive over the whole directory

You use chown a lot when deploying: for example, letting the web server (running as user www-data) own the source code directory.

Your current identity: id

id
uid=0(root) gid=0(root) groups=0(root)

id tells you which user you are (uid), your primary group (gid), and your other groups. Your permissions on a file depend on whether you're the owner, in the group, or "other". (root — uid 0 — bypasses all permission checks, which is why it's dangerous; Article 12.)

umask: default permissions when creating files

Why is a new file always 644 while a directory is 755? Because of umask — a "mask" that strips permissions away from the default value:

umask
0022

A umask of 022 means "remove the w permission from group and other". The system starts from 666 (file) / 777 (directory) and subtracts the umask, yielding 644 / 755. You rarely change umask, but knowing it explains why new files come out with those permissions.

Special permissions (know them so they don't surprise you)

Beyond rwx there are three special bits you'll see now and then:

  • setuid (s in the user's x position) — runs the file with the permissions of the file owner, not the person running it. For example, passwd needs setuid so ordinary users can change their own password.
  • setgid — similar for the group; on a directory, new files inherit the directory's group.
  • sticky bit (t) — on a directory like /tmp, only a file's owner can delete their own file (even though the directory is shared-writable).

You rarely set these yourself, but when you see rwsr-xr-x or /tmp with a t at the end, you'll know what they are.

🧹 Cleanup

cd /tmp && rm -f f.sh g.txt run.sh noexec.sh

Wrap-up

Every file has r/w/x permissions for the three groups user/group/other, read from the ls -l string. Permissions are expressed in octal (r=4, w=2, x=1 → 644, 755, 600...). Change them with chmod (octal for the full set, symbolic to tweak one permission), change ownership with chown, and umask decides the defaults. Remember: for a directory, x is "may enter", and deleting a file needs w on the parent directory. Most "Permission denied" errors are solved by reading this permission string correctly.

Article 8 (also a deep dive) moves to what's running on the system: processes and signals — how to view, manage, and terminate them.