2026
Linux File Permissions: chmod, chown and ACLs
Every file on Linux belongs to an owner and a group. Nine permission bits decide who can read it, write to it or execute it. ACLs extend that model when three classes are not enough. Here is how all of it works.
Every file on a Linux system belongs to someone. The kernel tracks that ownership and uses it to decide who is allowed to read the file, who can write to it and who can run it. This is not a policy layered on top of the operating system. It is built into the filesystem itself, evaluated on every single access.
Most of the time the defaults work. You create a file, it belongs to you and nobody else can write to it. The moment you start running services under dedicated accounts, sharing directories across teams or hardening a system, the defaults are not enough. You need to actually understand what the permission bits mean, how to change them deliberately and what ACLs let you express that the traditional model cannot.
This article covers the standard Unix permission model, the tools that manipulate it, the special bits that most people encounter by accident rather than design and the ACL layer that sits on top when three permission classes stop being enough.
The permission model
Every file has an owner (a user) and an owning group. Permissions are defined separately for three classes: the owner, the group and everyone else (called other). Within each class there are three permission bits: read, write and execute.
When a process tries to access a file, the kernel checks which class applies to that process. If the process is running as the file owner, the owner bits apply. If the process belongs to the file's group (but is not the owner), the group bits apply. Everyone else falls under other. Only one class ever applies at a time, starting from the most specific.
r — read
On a file, the holder can open it and read its contents. On a directory, the holder can list the names of entries inside it.
w — write
On a file, the holder can modify its contents or truncate it. On a directory, the holder can create, delete or rename entries inside it. Write on a directory does not by itself let you write to the files inside.
x — execute
On a file, the holder can run it as a program. On a directory, the holder can enter it and access the files inside. A directory without execute is one you can list but not actually use.
Reading permission strings
Run ls -l and the first column is a ten-character string. The first character is the file type. The next nine characters are three groups of three: owner permissions, group permissions, other permissions.
-rwsr-xr-x 1 root root 68208 Mar 14 10:21 /usr/bin/passwd
-File type. A hyphen means regular file. d means directory. l means symbolic link.
rwsOwner (root) can read, write and execute. The s instead of x means the setuid bit is set.
r-xGroup (root) can read and execute. No write.
r-xOthers can read and execute. No write.
A capital S in the execute position means the special bit is set but execute is not. A lowercase s means both are set. The same convention applies to the sticky bit, which shows as t or T in the other execute position.
chmod
chmod changes permission bits. There are two ways to write the permissions you want: symbolic mode, which describes changes using letters, and octal mode, which expresses the full permission set as a three-digit number.
Symbolic mode is useful when you want to add or remove a specific bit without touching the others. The format is [who][operator][permissions] where who is u (user/owner), g (group), o (other) or a (all three), the operator is + to add, - to remove or = to set exactly.
chmod u+x script.shAdd execute permission for the owner of the file.
chmod g-w config.ymlRemove write permission from the group.
chmod o=r README.txtSet others to read only, removing any existing write or execute.
chmod a+r public.txtAdd read for all three classes at once. a means user, group and other together.
chmod ug+rw shared.txtAdd read and write for both the owner and the group in one step.
Octal mode sets all nine permission bits at once as a number from 0 to 7 for each class. Each digit is the sum of read (4), write (2) and execute (1). A 7 means all three bits set. A 5 means read and execute but no write.
755Owner has full access. Group and others can read and execute but not write. Standard for executables and directories you want others to enter.
644Owner can read and write. Group and others can only read. Standard for regular files like configs and documents.
600Owner reads and writes. No access for anyone else. Used for private keys and sensitive config files.
700Owner has full access. Nobody else can do anything. Common for private directories.
777Everyone can read, write and execute. Rarely correct outside of temporary directories with a sticky bit in place.
Pass -R to apply a change recursively to everything inside a directory. Be deliberate with this. Applying 755 recursively to a directory tree will set execute on regular files too, which is rarely what you want. For recursive changes that treat files and directories differently, a find pipeline is more precise.
chown and chgrp
Permissions control what each class can do. Ownership determines which class a given process falls into. chown changes the owner, the group or both at once.
chown alice report.txtTransfer ownership of report.txt to alice. The group is not changed.
chown alice:devs report.txtSet the owner to alice and the group to devs in one command.
chown :devs report.txtChange only the group, leaving the owner as it is.
chown -R www-data:www-data /var/www/htmlRecursively set owner and group to www-data on the entire web root.
chgrp devs /srv/projectChange the group of a directory. Equivalent to chown :devs when you only need the group changed.
Only root can transfer ownership to another user. A regular user can change the group of a file they own, but only to a group they are a member of.
Special permission bits
Beyond the nine standard bits there are three more that modify how permissions behave. They are set with a fourth octal digit or with symbolic notation. Two of them are often misunderstood. One is quietly essential.
setuid (SUID)
When set on an executable file, the program runs with the permissions of the file owner rather than the user who launched it. This is how passwd lets ordinary users modify /etc/shadow. It shows up as an s in the owner execute position in ls output.
setgid (SGID)
On an executable, it runs with the group identity of the file group instead of the calling user's group. On a directory it has a different effect: new files created inside inherit the directory's group rather than the creator's primary group. Useful for shared project directories.
sticky bit
On a directory, only the file's owner, the directory owner or root can delete or rename a file inside it, even if other users have write permission on the directory. /tmp uses this. Without it, any user who can write to the directory could delete anyone else's files.
chmod u+s /usr/local/bin/mytoolSet the setuid bit on an executable so it runs as its owner.
chmod g+s /srv/teamSet the setgid bit on a directory so new files inherit the directory group.
chmod +t /tmpSet the sticky bit on a directory so users can only remove their own files.
chmod 4755 /usr/local/bin/mytoolOctal form: the leading 4 sets setuid. 755 is the standard permission pattern.
chmod 2775 /srv/teamOctal form: the leading 2 sets setgid. Common for shared directories.
chmod 1777 /tmpOctal form: the leading 1 sets the sticky bit. 777 makes it world-writable.
Access control lists
The standard Unix model gives you three classes. Sometimes that is not enough. You need one specific user to have read access to a file without making them part of the owning group. You need two different groups with different levels of access to the same directory. The traditional permission bits cannot express either of those requirements. ACLs can.
An ACL is a list of additional permission entries attached to a file. Each entry names a specific user or group and grants it a set of permissions independently of the standard bits. The standard bits remain in place. ACL entries sit alongside them as extensions.
Filesystem support
ACLs require filesystem support. ext4, XFS and Btrfs all support them by default on modern distributions. If getfacl or setfacl are not available, install the acl package. On some older setups you may need to mount the filesystem with the acl mount option, though most current kernels enable this automatically.
getfacl report.txtPrint the full ACL for report.txt, showing both standard permission bits and any extended entries.
setfacl -m u:alice:rw report.txtGrant alice read and write access to report.txt without changing the file's owner or standard permissions.
setfacl -m g:devs:r-- /var/log/app.logGive the devs group read-only access to the log file, on top of whatever the standard group bits say.
setfacl -x u:alice report.txtRemove the ACL entry for alice specifically. The file's standard permissions remain untouched.
setfacl -b report.txtRemove all extended ACL entries from the file, leaving only the standard permission bits.
setfacl -d -m g:devs:rw /srv/projectSet a default ACL on the directory. New files created inside will automatically inherit this entry.
# file: report.txt
# owner: lars
# group: staff
user::rw-
user:alice:rw-
group::r--
mask::rw-
other::---
The mask entry is worth understanding. It caps the effective permissions of all named entries and the owning group. Even if alice has rw in her entry, if the mask is r--, her effective access is read only. setfacl -m mask::rw adjusts it. Tools like chmod update the mask when you change group permissions on a file that has an ACL, which can be surprising the first time it happens.
A plus sign at the end of the permission string in ls -l output indicates that the file has an extended ACL. If you see it and cannot explain why, getfacl will show you what is there.
umask
When a new file is created, the kernel applies a default set of permissions before the creating program can change them. The umask controls which bits are stripped from those defaults.
The typical umask is 022. Files start with a maximum of 666 (read and write for everyone). The umask removes the bits it specifies, so 022 removes write for group and other, leaving 644. Directories start at 777, so a umask of 022 produces 755.
umaskPrint the current umask value.
umask 027Set the umask to 027. New files will be 640, new directories will be 750. Group has no write, others have nothing.
umask 077Strict umask. New files are 600, directories are 700. Nothing is visible to group or others by default.
Changes to umask in a shell session affect only that session. To make it persistent, set it in the user's shell profile or in /etc/profilefor a system-wide default.
Where it fits
File permissions are the first layer of access control on any Linux system. Before a process can read a config file, write a log, execute a binary or enter a directory, the kernel checks these bits. Everything else, SELinux, AppArmor, network ACLs, sits on top. If the basic ownership is wrong, none of the higher layers help.
In practice, most permission problems come from a handful of recurring mistakes: a service directory owned by root that a non-root service cannot write to, a private key file that is world-readable, a shared directory where users can delete each other's work because the sticky bit is missing. Understanding the model means you can diagnose these immediately rather than guessing at chmod 777 until something works.
ACLs extend this to situations where the three-class model is too blunt. They show up in shared workspaces, NFS mounts with multiple teams, CI systems that need read access to config files owned by a different service account. The core model and ACLs together cover the full range of what production Linux systems actually need to express.