Sign in
← Linux: basics
12 min · easy · Lesson 6 of 8

Permissions

rwx, octal, owners and groups. Why a script won't run even after chmod +x.

A script won't run even though you just did chmod +x. An app in a container reports Permission denied for a file that is definitely there. A coworker "fixed" everything with chmod -R 777. All three stories are about permissions, and you'll run into them in your first week of working with servers.

Where to practice

The examples below were captured in an ubuntu:24.04 container; you can spin up the same one:

docker run --rm -it ubuntu:24.04 bash

Inside, you're root, and root bypasses read and write checks. It reads a file with mode 000 without an error. So create a regular user first and check permissions as that user:

useradd -m -s /bin/bash deploy
su deploy -c 'cat /etc/shadow'
cat: /etc/shadow: Permission denied

su deploy -c '<command>' runs one command as deploy. --rm removes the container after exit.

Three categories, three permissions

Every file has an owner (user) and a group (group). Permissions are set separately for three categories:

And three kinds of access:

One category applies, checked top to bottom. If you're the owner, u applies, even if the group has more permissions. Not the owner but in the file's group means g. Otherwise o.

Reading ls -l

-rwxr-xr--  1 deploy  www-data  4096 May 29 12:00 deploy.sh

The first block, -rwxr-xr--, breaks down like this:

-     rwx        r-x       r--
type  owner      group     other

Octal form

The same permissions can be written as a number. Each category is one digit, the sum of its bits:

Add them up within a category: rwx = 4+2+1 = 7, r-x = 4+1 = 5, r-- = 4. So -rwxr-xr-- is 754.

Common combinations worth recognizing on sight:

OctalPermissionsWhere it shows up
644rw-r--r--a regular file: owner writes, everyone reads
600rw-------a private file: owner only (SSH keys)
755rwxr-xr-xa script or binary: everyone runs it, only the owner changes it
700rwx------a private directory or script for the owner only
777rwxrwxrwxeverything for everyone. Almost always a mistake, don't do this

Who you are and what the file has

id shows your own uid/gid and groups, and stat gives the full picture of a file:

su deploy -c id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy)
stat /usr/bin/passwd
  File: /usr/bin/passwd
  Size: 72056     	Blocks: 144        IO Block: 4096   regular file
...
Access: (4755/-rwsr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
...

stat shows permissions both in octal (4755) and in symbolic form, plus the owner and group. More on the leading 4 below, in "Special bits". Without id you don't know which uid you're working under, and so you don't know whether you fall into category u, g, or o.

A shorter form for several files at once: stat -c '%a %U %n' <files> prints the octal mode, owner, and name on one line.

Commands

chmod 755 deploy.sh         # octal form
chmod +x deploy.sh          # add execute for every category
chmod u+x,go-w deploy.sh    # symbolic form: targeted changes
chown deploy file           # change the owner
chown deploy:www-data file  # owner and group
chgrp www-data file         # group only
chmod -R 755 dir            # recursive: the directory and everything inside

Only root can give a file to another owner (chown). A regular user can change their file's group, but only to a group they already belong to. Permissions (chmod) can be changed by the file's owner or root. You can't change a file that isn't yours:

chmod: changing permissions of '/etc/hostname': Operation not permitted

Be careful with -R. chmod -R 755 hands out x and read access to every single file, including keys that should be 600.

Directory permissions work differently

For a directory, the bits mean something else:

r and x on a directory work independently. With only r (744), ls shows the names, but cat on any file inside answers Permission denied. With only x (711) it's the other way around: you can read a file if you already know its name, but ls on the directory is blocked.

The catch: to read the file /a/b/file.txt, you need x on /, /a, and /a/b, even if the file itself has the right permissions. Without x on any directory along the way, you can't reach the content. namei -l shows the whole path with every link's permissions:

namei -l /a/b/file.txt
f: /a/b/file.txt
drwxr-xr-x root root /
drwx------ root root a
drwxr-xr-x root root b
-rw-r--r-- root root file.txt

Here deploy can't reach the file: on /a, others don't even have x.

Special bits

umask

New files start from base permissions 666, and directories from 777, and the bits set in umask are subtracted from that base. A typical umask 022 removes w for group and others: files come out as 644, directories as 755. With umask 077, new files end up 600. The umask command shows the current value.

Common mistakes

What to remember

rwx for u/g/o. In octal: r=4, w=2, x=1; recognize 755, 644, 600 on sight.

On a directory, x means permission to enter. Without it you can't reach the files inside, and you need it on every directory along the path.

chmod +x won't help if a directory on the path is closed off, the filesystem is mounted with noexec, or a Windows \r is stuck in the shebang. 777 is almost always a mistake.

In a container, permissions look at the numeric uid, which is why a bind mount can give you Permission denied.

The next lesson covers pipes and redirects: how to connect commands and redirect output.

What you'll need for the tasks

Done reading?

Mark the lesson as read to move your track progress forward.

Go through it with an AI agent

The agent explains anything unclear in plain words and walks you through 2 labs for this lesson. This track is free.

Connect an agent

Tell the agent: use MCP izi, give me lesson linux-basics-06-permissions