Linux ACL (Access Control Lists) Guide: setfacl & getfacl Explained

A comprehensive deep dive into Linux Access Control Lists, solving complex permission challenges with setfacl and getfacl.

Introduction: The Evolution of Linux Permissions

If you have spent any amount of time managing a Linux system, you are likely intimately familiar with standard file permissions. The tried-and-true UGO (User, Group, Other) model, managed via the chmod and chown commands, has been the bedrock of Unix and Linux security for decades. It is elegant, simple, and covers about 90% of daily use cases.

But what happens when you hit that other 10%? What happens when your organization scales, your collaboration requirements become more complex, and a single file needs to be read by Alice, written by Bob, executed by Charlie, and hidden from Dave—while still being owned by the Web team?

This is where standard permissions hit a brick wall. And this is exactly where Linux ACL (Access Control Lists) enter the picture to save the day.

In this massive, comprehensive 3000+ word guide, we will explore everything there is to know about access control lists in Linux. We will dissect the limitations of standard permissions, introduce the power of fine-grained control via setfacl and getfacl, demystify the complex relationship between ACL masks and standard chmod values, and walk through real-world enterprise architectures where default ACLs are absolute lifesavers.

By the end of this guide, you will transition from a Linux permissions novice to an ACL architect capable of designing secure, multi-tenant file systems.

🚀 Quick Solution Box

Need to apply an ACL right now? Here are the most common commands you'll need:

  • View ACLs: getfacl filename.txt
  • Give a specific user Read/Write: setfacl -m u:username:rw filename.txt
  • Give a specific group Read/Execute: setfacl -m g:groupname:r-x filename.txt
  • Remove a specific user's ACL: setfacl -x u:username filename.txt
  • Remove ALL ACLs on a file: setfacl -b filename.txt
  • Set a Default ACL on a directory: setfacl -d -m u:username:rwx /var/shared

Why Standard UGO Permissions Fail (The Problem)

To truly appreciate Linux ACLs, we must first understand the fundamental limitations of the standard POSIX permission model. As detailed in our Linux Permissions Complete Guide, every file and directory in Linux has three distinct sets of permissions:

  • User (u): The owner of the file.
  • Group (g): The group that owns the file.
  • Other (o): Everyone else on the system.

For each of these three entities, you can assign Read (r), Write (w), or Execute (x) privileges.

This model is incredibly fast for the kernel to process, which was crucial in the early days of Unix. However, it imposes a rigid, one-dimensional hierarchy. Let's look at a practical scenario where this falls apart.

The "Three-Department" Dilemma

Imagine you are the system administrator for a media company. You have a highly sensitive financial report file, Q4_Earnings.pdf.

  • The Finance Director (Alice) created the file and needs full Read/Write access.
  • The Executive Group (execs) needs Read-Only access to review it.
  • The Legal Auditor (Bob) needs Read/Write access to add his compliance notes.
  • The Marketing Manager (Charlie) needs Read-Only access to prepare a press release.
  • Everyone else in the company must have zero access.

Let's try to solve this using standard `chmod` and `chown`.

First, we give Alice ownership, and assign the file to the execs group:

chown alice:execs Q4_Earnings.pdf
chmod 640 Q4_Earnings.pdf
# -rw-r----- 1 alice execs Q4_Earnings.pdf

So far, so good. Alice can read and write (rw). The execs group can read (r). Others have no access (-).

But wait—how do we give Bob (the Legal Auditor) read/write access? We can't change the file owner to Bob, because Alice needs it. We can't change the group to Bob's primary group, because the execs need it.

We could create a brand new secondary group called finance_legal_audit_team, add Alice and Bob to it, change the file's group to that new group, and give it `rw-` permissions. But then the execs group loses their access!

We could add the execs to that new group, but then they get Write access, which violates our security policy (they only need Read).

We could just use "Other" permissions (chmod o+rw), but then literally anyone with a login on the server can read and edit the financial document, which is a catastrophic security breach.

As you can see, standard permissions force you into creating complex, bloated group structures that become impossible to manage, or worse, force you to loosen security by relying on world-writable permissions.

How Access Control Lists (ACLs) Solve the Problem

Access Control Lists (ACLs) break the rigid "one owner, one group" limitation. They allow you to attach a list of explicit permissions for an arbitrary number of specific users and specific groups directly to a file or directory's inode metadata.

With ACLs, our impossible scenario becomes trivial. We simply keep Alice as the owner, keep execs as the group, and explicitly tell the filesystem: "Oh, by the way, Bob gets RW, and Charlie gets R."

No messy secondary group creation, no compromising on security, and complete fine-grained control.

Prerequisites: Filesystem Support

Modern Linux distributions (Ubuntu, Debian, RHEL, AlmaLinux, Rocky) format file systems (like ext4, XFS, and Btrfs) with ACL support enabled by default.

However, if you are working on an older system or a custom mount point, you may need to ensure the acl mount option is enabled in your /etc/fstab file.

# Example /etc/fstab entry enabling ACL
UUID=12345678-1234-1234-1234-123456789abc /data ext4 defaults,acl 0 2

You can remount a partition live to enable ACLs without rebooting:

sudo mount -o remount,acl /data

You will also need the ACL toolkit installed. Most systems have it, but if you don't, you can install it via your package manager:

# On Debian/Ubuntu
sudo apt-get update && sudo apt-get install acl

# On RHEL/CentOS/Fedora
sudo dnf install acl

Understanding the `+` Symbol in `ls -l`

When you apply an ACL to a file, standard POSIX tools need a way to warn you that standard `ugo` permissions are no longer telling the whole story.

Let's look at the output of a standard directory listing:

ls -l /data/reports
-rw-r--r--  1 alice finance 1024 May 12 10:00 standard_file.txt
-rw-rwxr--+ 1 alice finance 2048 May 12 10:05 acl_secured_file.txt

Notice the plus sign (+) at the very end of the permission string for acl_secured_file.txt.

This plus sign is a critical indicator. It screams at the system administrator: "Hey! The permissions you see here (rw-rwxr--) are a lie! There is an Access Control List attached to this file that overrides or extends these basic permissions."

Whenever you see that `+`, you must immediately use the getfacl command to discover the true permissions of the file. Relying on `chmod` or `ls` when a `+` is present will lead to massive confusion.

How to View ACLs: Using `getfacl`

The getfacl (Get File Access Control Lists) command is your x-ray vision for Linux permissions. It reveals the exact access rights for every user and group attached to a file.

Let's run it on a basic file that doesn't have any extended ACLs applied yet:

$ getfacl standard_file.txt
# file: standard_file.txt
# owner: alice
# group: finance
user::rw-
group::r--
other::r--

Even without extended ACLs, getfacl provides a clean, easy-to-read breakdown of the standard permissions.

  • Lines starting with # are metadata comments, showing the filename, owning user, and owning group.
  • user:: represents the base standard permissions of the file owner (alice). Notice there is no name between the colons. This means it applies to the base file owner.
  • group:: represents the base standard permissions of the owning group (finance).
  • other:: represents the base permissions for everyone else.

Now, let's look at the output for a file that does have extended ACLs:

$ getfacl Q4_Earnings.pdf
# file: Q4_Earnings.pdf
# owner: alice
# group: execs
user::rw-
user:bob:rw-
user:charlie:r--
group::r--
group:legal:rwx
mask::rwx
other::---

This output is much richer. Here is how to parse the new entries:

  • user:bob:rw-: A Named User entry. The specific user `bob` is granted read and write access, regardless of who owns the file or what group it belongs to.
  • user:charlie:r--: Another Named User entry. The user `charlie` is granted read-only access.
  • group:legal:rwx: A Named Group entry. The specific group `legal` (which is not the primary group owner of the file) is granted read, write, and execute access.
  • mask::rwx: The ACL Mask. This is a crucial concept that we will explore in depth shortly. It defines the absolute maximum permissions allowed for all named users and groups.

How to Set ACLs: Using `setfacl`

The setfacl (Set File Access Control Lists) command is the workhorse tool you will use to create, modify, and delete ACL entries.

The basic syntax relies heavily on the -m (modify) flag, followed by a rule definition. The rule definition takes the format:

entity_type:entity_name:permissions

1. Granting Access to a Specific User

To give our legal auditor, Bob, read and write access to our file, we use u: (for user), followed by his username, followed by rw.

setfacl -m u:bob:rw Q4_Earnings.pdf

If we want to give multiple users permissions in a single command, we can separate the rules with a comma:

setfacl -m u:bob:rw,u:charlie:r Q4_Earnings.pdf

2. Granting Access to a Specific Group

Similarly, to grant access to a secondary group, we use g: (for group). Let's give the IT department read access so they can back up the file:

setfacl -m g:it_department:r Q4_Earnings.pdf

3. Modifying Existing ACLs

The -m flag stands for "modify," meaning it doesn't just create new ACLs, it updates existing ones. If Bob currently has rw- access, and we realize he shouldn't be allowed to edit the file anymore, we simply run a new modify command to overwrite his entry with read-only access:

setfacl -m u:bob:r Q4_Earnings.pdf

Running getfacl will now show user:bob:r--.

4. Recursive ACL Application

Just like `chmod -R` and `chown -R`, you will often need to apply ACLs to an entire directory tree. You can achieve this using the uppercase -R flag:

setfacl -R -m u:bob:rw /data/financial_records/

Warning: Be careful with recursive ACLs, especially when granting execute (x) permissions. If you apply -R -m u:bob:rwx to a directory, you will make every single text file inside that directory executable, which is generally a bad practice.

To solve this, setfacl supports an uppercase X permission. The uppercase X will apply execute permission only to directories (so the user can cd into them), and to files that already have standard execute permissions set for someone. It will ignore regular files like `.txt` or `.pdf`.

# Safe recursive application:
setfacl -R -m u:bob:rwX /data/financial_records/

The ACL Mask: The Gatekeeper of Extended Permissions

If you look closely at the output of a file with extended ACLs, you'll see a line called mask::. You will also notice that if you run a standard `ls -l` on the file, the group permissions column has suddenly changed to match the mask.

This is the most confusing aspect of Linux ACLs, and understanding it is what separates amateurs from professionals.

When you add an ACL to a file, Linux repurposes the standard "group" permission bits in the file's inode to store the ACL Mask.

What is the ACL Mask?
The mask is the absolute ceiling, the maximum limit, of permissions that can be granted to any named user, any named group, and the base owning group. (The base file owner and base "other" are unaffected by the mask).

The Mask in Action

Let's look at an example. We give Bob read, write, and execute permissions.

$ setfacl -m u:bob:rwx project_plan.sh
$ getfacl project_plan.sh
user::rwx
user:bob:rwx
group::r-x
mask::rwx
other::r-x

The mask is automatically recalculated to `rwx` to accommodate Bob's new permissions. Bob can read, write, and execute the file.

But what happens if a Junior SysAdmin comes along, sees this script, gets nervous, and tries to lock it down using standard chmod? They run our trusty Chmod Calculator and decide they want the group to only have read access, so they run:

chmod 644 project_plan.sh

Remember how we said the "group" bits in `chmod` actually control the ACL Mask when ACLs are active? By running chmod 644 (where the group gets 4, or `r--`), the sysadmin has inadvertently crushed the ACL mask down to read-only! Let's look at getfacl now:

$ getfacl project_plan.sh
user::rw-
user:bob:rwx           #effective:r--
group::r-x             #effective:r--
mask::r--
other::r--

Notice what happened. Bob's ACL entry still officially says rwx. But getfacl has added a warning comment: #effective:r--.

Because the mask acts as a ceiling, and the mask is now `r--`, Bob's permissions are filtered through the mask. The system asks: "Bob wants rwx. The mask allows r--. What is the intersection?" The answer is read-only. Bob has lost his write and execute abilities, despite his ACL entry remaining intact.

Managing the Mask Safely

To prevent standard `chmod` from breaking your complex ACL structures, you should avoid using `chmod` on files with a `+` in their `ls` output.

If you need to change the mask explicitly without touching the base permissions, you can set it directly with setfacl using the m: entity type:

# Force the mask to allow read and write
setfacl -m m::rw project_plan.sh

You can also use the -n (no-recalculate) flag when modifying ACLs if you explicitly do not want the system to auto-elevate the mask to accommodate a new user rule.

Default ACLs: Inheriting Permissions (`-d`)

While setting ACLs on individual files is powerful, it is tedious. In enterprise environments, the most common requirement is a "Shared Collaborative Directory."

Imagine a directory called /var/marketing_assets/. You want everyone in the `marketing` group to have read/write access, and everyone in the `sales` group to have read-only access.

You can apply those ACLs to the folder easily. But what happens when Alice from marketing creates a brand new file inside that folder? By default, Linux creates the file with her primary user and group ownership, and standard `umask` permissions. Bob from marketing might not be able to edit Alice's new file!

Historically, sysadmins tried to hack around this by setting the setgid (SGID) bit on the directory (chmod g+s). This forces new files to inherit the group ownership of the parent directory. While helpful, it only solves half the problem (group ownership), and completely ignores our `sales` group read-only requirement.

The Solution: `-d` (Default ACLs)

A Default ACL is applied to a directory. It does not dictate who can access the directory itself (that is still handled by regular ACLs). Instead, a Default ACL serves as a template. Every new file or subdirectory created inside that directory will automatically inherit the Default ACL.

Let's set up our ultimate marketing shared folder:

# Step 1: Set regular ACLs so existing users can access the directory right now
setfacl -m g:marketing:rwx,g:sales:rx /var/marketing_assets/

# Step 2: Set DEFAULT ACLs so future files inherit these permissions
setfacl -d -m g:marketing:rwx,g:sales:rx /var/marketing_assets/

Let's verify our configuration:

$ getfacl /var/marketing_assets/
# file: var/marketing_assets/
# owner: root
# group: root
user::rwx
group::r-x
group:marketing:rwx
group:sales:r-x
mask::rwx
other::r-x
default:user::rwx
default:group::r-x
default:group:marketing:rwx
default:group:sales:r-x
default:mask::rwx
default:other::r-x

Look at all the entries prefixed with default:.

Now, when Alice creates campaign.txt inside this folder, the file will automatically be generated with user:alice:rw-, but it will also automatically receive the ACL group:marketing:rw- and group:sales:r-- (scaled down to avoid making files automatically executable).

Default ACLs are the absolute best way to manage shared directories in Linux, far surpassing the limitations of the old SGID trick.

Removing and Cleaning up ACLs (`-x`, `-b`)

Permissions change. Employees leave the company, roles shift, and eventually, you need to revoke access. `setfacl` provides robust tools for removing rules.

Removing a Specific Entry (`-x`)

To remove a specific user or group from an ACL, use the -x flag. For example, if Bob moves to a different department and no longer needs access:

setfacl -x u:bob Q4_Earnings.pdf

Notice that you do not specify permissions (`:rw`) when using `-x`; you simply specify the entity you want to delete.

Removing ALL Extended ACLs (`-b`)

Sometimes, an ACL structure becomes a tangled mess, and you just want to nuke it from orbit and start fresh with standard UGO permissions.

The -b (remove all extended ACL entries) flag is your panic button. It strips away all named users, named groups, and masks, returning the file to its base standard permissions.

$ setfacl -b Q4_Earnings.pdf
$ ls -l Q4_Earnings.pdf
-rw-r--r-- 1 alice execs 2048 May 12 10:05 Q4_Earnings.pdf

The + symbol is gone, and sanity is restored.

Removing Default ACLs (`-k`)

If you want to keep the access ACLs on a directory, but stop future files from inheriting permissions, use the -k flag to remove specifically the default ACLs:

setfacl -k /var/marketing_assets/

Backing Up and Restoring ACLs

If you are performing a major migration, moving files between servers, or just performing scheduled system backups via `tar` or `rsync`, you must be extremely careful. Many standard backup utilities strip ACL metadata by default!

For instance, if you use `tar`, you must include the --acls flag. If you use `rsync`, you must include the -A flag.

If you want to be completely safe, it is considered a best practice to dump your ACL configuration to a plain text file before any major migration. getfacl makes this incredibly easy.

Creating an ACL Backup

getfacl -R /var/www/html/ > /root/www_acls_backup.acl

This command recursively reads every file and directory in `/var/www/html/` and writes their exact ACL specifications into a flat text file.

Restoring from a Backup

If disaster strikes, and someone accidentally runs `setfacl -R -b /var/www/html/`, destroying all your fine-grained permissions, you can restore them instantly using the --restore flag.

cd /
setfacl --restore=/root/www_acls_backup.acl

Note: Because the backup file contains relative paths, you generally need to execute the restore command from the root directory (`/`) or the directory from which the backup was originally taken.

Best Practices for Linux ACL Management

With great power comes great responsibility. While ACLs solve complex problems, they can also create administrative nightmares if implemented haphazardly. Here are the golden rules of ACL management:

  1. Use Standard Permissions First: Do not use ACLs if standard `chmod`/`chown` can achieve the goal cleanly. Complexity is the enemy of security. Rely on standard groups as your primary defense layer.
  2. Favor Groups Over Users: Try to avoid assigning ACLs directly to named users (e.g., `u:bob:rw`). Instead, create a functional group (e.g., `project_alpha_read`), assign the ACL to that group (`g:project_alpha_read:r`), and add Bob to the group. When Bob leaves, you just remove him from the group in `/etc/group` without having to hunt down thousands of files across the filesystem to run `setfacl -x u:bob`.
  3. Use Default ACLs for Directories: If multiple people are collaborating in a folder, always use Default ACLs (`-d`) on the parent directory. Do not rely on cron jobs running `setfacl -R` every 5 minutes to fix permissions on newly created files.
  4. Beware the Mask: Educate your team that standard `chmod` destroys ACL masks. If an ACL is present (the `+` sign), use `setfacl` to modify permissions, not `chmod`.
  5. Audit Regularly: Periodically run scripts that pipe `getfacl -R /sensitive_data` to a log file, and diff it against known good states to detect unauthorized permission creep.

Conclusion & Next Steps

Linux Access Control Lists are an indispensable tool in the modern system administrator's utility belt. By moving beyond the limitations of standard UGO permissions, `setfacl` and `getfacl` empower you to design granular, secure, and highly functional shared environments.

Whether you are isolating processes in a multi-tenant web server, creating collaborative drop-boxes for media teams, or enforcing strict read-only compliance for auditing systems, ACLs provide the exact precision you need.

However, ACLs are just one piece of the Linux security puzzle. To truly master server security, you must understand how ACLs interact with underlying standard permissions, sticky bits, and SUID/SGID.

If you haven't already, we highly recommend reading our foundational Linux Permissions Complete Guide. And if you need to calculate base permissions quickly to ensure your ACL masks aren't being restricted, bookmark our free Chmod Calculator tool.