Skip to main content

Linux File Permissions: chmod, chown, SUID and ACL

Security · 19.04.2026 · 5 min read
Illustration for “Linux File Permissions: chmod, chown, SUID and ACL”

File permissions are a fundamental Linux security mechanism. Wrong permissions can leak config files with passwords or let an attacker execute code.

Numeric chmod notation

NumberPermissionsUse case
777rwxrwxrwxNever! Dangerous
755rwxr-xr-xDirectories, scripts
644rw-r--r--HTML, PHP files
600rw-------Private keys, config files
400r--------Read-only for the owner
find /var/www -type f -exec chmod 644 {} \;
find /var/www -type d -exec chmod 755 {} \;
chmod u+x script.sh
chmod g-w config.php
chown -R www-data:www-data /var/www/site/

Symbolic notation and common mistakes

Symbolic notation changes permissions relative to the current ones instead of setting them all at once: chmod u+x adds execute permission for the owner without touching group or other permissions. This is more convenient than numeric notation when you only need to change one bit without first finding out the current value of the rest.

The letters u, g, o and a stand for the owner (user), the group, others, and everyone at once (all); the signs +, - and = add, remove or set permissions exactly. For example, chmod go=r file sets group and others to exactly read permission, whatever the previous value was.

Mistake: chmod -R 777 as a quick fix

Recursive 777 on the whole site directory "to finally make it work" opens write access to any system user, including the web server of other sites on the same host and any process that gains access to the system. The right approach is to find who actually lacks permissions (usually the owner of the web server process) and grant access precisely through chown or ACL, not to everyone at once.

Mistake: identical permissions for files and directories

Execute permission (x) on a directory means the right to enter it and open files by name — it is not the same as running a program, as it is for a file. A directory with 644 instead of 755 will not let you into it even with correct permissions on the files inside, while a script file with 755 when 644 was needed allows it to be executed if the web server is configured to execute files by extension.

Special bits: SUID, SGID, Sticky

# SUID - run with the file owner's permissions
chmod u+s /usr/bin/program  # chmod 4755
# ls: -rwsr-xr-x

# SGID - inherit the directory's group
chmod g+s /shared/dir  # chmod 2755

# Sticky bit - only the owner can delete the file
chmod +t /tmp  # chmod 1777
# ls: drwxrwxrwt

# Find SUID files (potential risk)
find / -perm -4000 -type f 2>/dev/null

ACL - extended permissions

apt install acl -y
setfacl -m u:deploy:rw /var/www/config.php
setfacl -Rm g:devteam:rwx /var/www/project/
getfacl /var/www/config.php
setfacl -b /var/www/config.php  # Remove ACL

chmod or ACL: which to choose

TaskRegular chmod/chownACL
A single owner and a single groupEnoughOverkill
Access for several users with different permissions on one fileNot expressibleFits - a separate entry for each
Default permissions for new files in a shared directoryOnly through SGID on the groupDefault ACL sets exact permissions for several entities at once

When ACL will not work

  • The filesystem is mounted without the acl option — most modern ext4 filesystems enable it by default, but old entries in /etc/fstab or network mounts may not set it explicitly.
  • Some network filesystems and old versions of NFS support ACL only partially or not at all — permissions then apply only at the regular chmod level.
  • Archivers and copy tools without special flags (for example, plain cp without --preserve in some cases) may not carry ACL entries along with the file — check with getfacl after moving important files to a new location.

Verifying the result

  1. Run stat -c "%a %U %G" /var/www/site/config.php — the numeric permissions and the owner should match what you set.
  2. For ACL, run getfacl file and confirm the expected user: or group: entry is present in the output.
  3. Try logging in as an unprivileged user and reading a file with 600 permissions owned by someone else — access should be denied.
  4. After a recursive permission change, spot-check several files and directories with ls -la rather than just the top-level directory — recursive commands sometimes stumble on files with unusual names.
Golden rule: the principle of least privilege - grant only the permissions that are needed. For a web server: files 644, directories 755, config files 600. Never 777.

File permissions are only one layer of server security; tracking who changed them and when is covered in auditing events with auditd, and additional access separation at the process level is covered in setting up SELinux and AppArmor.

Was this article helpful?
← Back to Knowledge Base Ask Support