ACL — quick reference
Inspect (getfacl)
Read current ACL entries before changing permissions — safe on any file you can read.
| When to use | Command |
|---|---|
| Show full ACL including mask and defaults | getfacl /path/to/file |
| Access ACL only (skip default entries) | getfacl -a /path/to/dir |
| Default ACL only (directories) | getfacl -d /path/to/dir |
| Show effective rights after mask limits | getfacl -e /path/to/file |
| List ACLs under a tree | getfacl -R /path/to/tree |
| Backup ACLs for restore later | getfacl -R /path > acls.backup |
Modify (setfacl)
Add or change named user/group entries without replacing the whole ACL.
| When to use | Command |
|---|---|
| Grant read to one user on a file | sudo setfacl -m u:alice:r-- /data/report.txt |
| Grant traverse on a directory (list + enter) | sudo setfacl -m u:alice:r-x /data/shared |
| Grant a group write on a file | sudo setfacl -m g:developers:rw- /data/app.conf |
| Set mask explicitly (cap named user/group rights) | sudo setfacl -m m::r-- /data/file |
| Replace entire ACL from one string | sudo setfacl --set="u::rw-,g::r--,o::---" /data/file |
| Apply ACL changes down a directory tree | sudo setfacl -R -m u:alice:r-- /data/tree |
| Dry-run — print what would change | sudo setfacl --test -m u:alice:rwx /data/file |
Default ACLs (setfacl -d)
Default entries apply only to directories and are inherited by new files and subdirectories.
| When to use | Command |
|---|---|
| New files in a dir inherit read for a user | sudo setfacl -d -m u:alice:r-- /data/shared |
| Set access and default ACL in one command | sudo setfacl -m u:alice:r-x -d -m u:alice:r-- /data/shared |
| Remove default ACL from a directory | sudo setfacl -k /data/shared |
Remove (setfacl)
Drop extended rules while keeping owner/group/other bits from chmod.
| When to use | Command |
|---|---|
| Remove one named user entry | sudo setfacl -x u:alice /data/file |
| Remove one named group entry | sudo setfacl -x g:developers /data/file |
| Strip all extended ACL entries | sudo setfacl -b /data/file |
| Restore ACLs from a getfacl backup | sudo setfacl --restore=acls.backup |
Full replace (chacl)
Low-level tool that replaces the entire ACL in one shot — prefer setfacl for day-to-day edits.
| When to use | Command |
|---|---|
| Replace ACL with a declarative rule string | sudo chacl "u::rw-,g::r--,o::---" /data/file |
| Remove all ACLs (reset to mode bits only) | sudo chacl -B /data/file |
Filesystem must support ACLs (ext4 with acl mount option, or xfs — both default on Ubuntu 25.04). ls -l shows a + after the mode when extended ACLs exist.
ACL — command syntax
setfacl synopsis from setfacl --help on Ubuntu 25.04 (acl 2.3.2):
setfacl [-bkndRLP] { -m|-M|-x|-X ... } file ...
-m, --modify=acl modify the current ACL(s) of file(s)
-x, --remove=acl remove entries from the ACL(s) of file(s)
-b, --remove-all remove all extended ACL entries
-d, --default operations apply to the default ACL
-R, --recursive recurse into subdirectories
--set=acl set the ACL, replacing the current ACL
--restore=file restore ACLs (inverse of getfacl -R)getfacl reads the same entry format (u:alice:r--, g:developers:rw-, m::r--, d:u:alice:r-- for defaults). Changes are stored in the filesystem extended attribute system.posix_acl_access (and system.posix_acl_default on directories).
ACL — command examples
Essential Inspect ACLs with getfacl (baseline)
Before changing permissions, read what the kernel enforces. getfacl shows owner, group, mask, and any named users — more detail than ls -l.
Create a test file and view its ACL:
echo "quarterly report" | sudo tee /tmp/acl-demo/report.txt > /dev/null
sudo chmod 600 /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txtSample output:
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
group::---
other::---Only the three classic entries appear — no + in ls -l yet. This is the baseline before adding named users.
Essential Grant read access to one user (setfacl -m)
When chmod cannot give a second user read access without opening the file to everyone, add a named user ACL entry.
Grant read to nobody without changing owner or group:
sudo setfacl -m u:nobody:r-- /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txt
ls -l /tmp/acl-demo/report.txtSample output:
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
user:nobody:r--
group::---
mask::r--
other::---
-rw-r--r--+ 1 root root 17 Jul 1 15:48 /tmp/acl-demo/report.txtThe + after the mode means extended ACLs are present. mask::r-- caps what named users and the owning group can actually use.
Essential Verify effective permissions as another user
Confirm the ACL works from the recipient's point of view — getfacl alone does not prove access.
Test read as nobody:
sudo -u nobody cat /tmp/acl-demo/report.txtSample output:
quarterly reportIf this fails, check the mask with getfacl -e — a permissive user entry can still be capped by mask::r--.
Common Default ACL on a shared directory (inheritance)
Access ACLs control the directory itself; default ACLs define what new files inside inherit. This is the usual pattern for team folders on ext4 or xfs.
Set access and default ACL on a directory:
sudo mkdir -p /tmp/acl-demo/shared
sudo chmod 700 /tmp/acl-demo/shared
sudo setfacl -m u:nobody:r-x -d -m u:nobody:r-- /tmp/acl-demo/shared
getfacl /tmp/acl-demo/sharedSample output:
# file: tmp/acl-demo/shared
# owner: root
# group: root
user::rwx
user:nobody:r-x
group::---
mask::r-x
other::---
default:user::rwx
default:user:nobody:r--
default:group::---
default:mask::r--
default:other::---Create a new file inside and confirm inheritance:
sudo touch /tmp/acl-demo/shared/newfile.txt
getfacl /tmp/acl-demo/shared/newfile.txtSample output:
# file: tmp/acl-demo/shared/newfile.txt
# owner: root
# group: root
user::rw-
user:nobody:r--
group::---
mask::r--
other::---Default ACL does not retroactively change files that already existed — only new entries.
Common Remove one ACL entry (setfacl -x)
Revoke access for one user while keeping other ACL rules intact.
Remove the nobody entry from the report file:
sudo setfacl -x u:nobody /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txt
ls -l /tmp/acl-demo/report.txtSample output:
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
group::---
mask::---
other::---
-rw-------+ 1 root root 17 Jul 1 15:48 /tmp/acl-demo/report.txtThe + can remain briefly until the last extended entry is gone; setfacl -b clears all extended entries at once.
Common Mask limits effective rights (getfacl -e)
A user entry may grant rwx but the mask can silently reduce effective access — a common troubleshooting surprise.
Set a wide user ACL with a tight mask:
echo secret | sudo tee /tmp/acl-demo/mask-demo.txt > /dev/null
sudo chmod 600 /tmp/acl-demo/mask-demo.txt
sudo setfacl -m u:nobody:rwx,m::r-- /tmp/acl-demo/mask-demo.txt
getfacl -e /tmp/acl-demo/mask-demo.txtSample output:
# file: tmp/acl-demo/mask-demo.txt
# owner: root
# group: root
user::rw-
user:nobody:rwx #effective:r--
group::--- #effective:---
mask::r--
other::---#effective:r-- shows the kernel only allows read despite rwx on the user line. Raise the mask with sudo setfacl -m m::rwx FILE if write is intended.
Advanced Apply ACLs recursively (-R)
Large project trees sometimes need the same named-user rule on every file — -R walks the directory.
Apply read for nobody under the demo tree:
sudo setfacl -R -m u:nobody:r-- /tmp/acl-demo
getfacl /tmp/acl-demo/shared/newfile.txtSample output:
# file: tmp/acl-demo/shared/newfile.txt
# owner: root
# group: root
user::rw-
user:nobody:r--
group::r--
mask::r--
other::r--Use -R carefully on production trees — it touches every file. Pair with getfacl -R backup before bulk changes.
Advanced chacl replaces the entire ACL (advanced reset)
chacl is not incremental — each run replaces the whole ACL. Use it for a clean reset or a declarative policy string, not for small edits.
Inspect, then replace with chacl:
getfacl /tmp/acl-demo/report.txt
sudo chacl "u::rw-,g::r--,o::---" /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txtSample output after chacl:
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
group::r--
mask::rw-
other::---Named user entries from earlier setfacl runs are gone. For day-to-day work, prefer setfacl -m and setfacl -x. To strip all extended ACLs, setfacl -b or chacl -B also work.
Clean up lab files when finished:
sudo rm -rf /tmp/acl-demoACL — when to use / when not
| Use ACLs (setfacl/getfacl) when | Use something else when |
|---|---|
|
|
setfacl vs chmod vs chacl
| setfacl / getfacl | chmod | chacl | |
|---|---|---|---|
| Role | Per-user/group ACL entries | Owner, group, other mode bits | Full ACL replace |
| Incremental edits | Yes (-m, -x) |
Yes (mode digits) | No — overwrites all |
| Default inheritance | Yes (-d) on directories |
No | Yes (in full ACL string) |
| Inspect | getfacl |
ls -l, stat |
getfacl / chacl -l |
Linux chmod +a |
N/A — use setfacl |
GNU chmod has no +a (macOS/BSD syntax) |
N/A |
Start with chmod and chown. Reach for setfacl when the classic triple is too coarse.
Related commands
Nearby tools for the same permission workflow — mode bits, ownership, and extended ACLs.
Browse the full index in our Linux commands reference.
ACL — interview corner
Practice these before exams or standups. Each card explains the idea in plain language, then ends with a short answer you can say aloud.
What is a POSIX ACL in Linux?
A POSIX ACL extends the classic owner/group/other model. Instead of only three permission classes, you can attach rules for named users and named groups on a single file or directory.
The kernel still stores base mode bits (what chmod sets), but when ACLs exist it also reads extended attributes — on ext4 and xfs you will see system.posix_acl_access. ls -l adds a + after the mode when those extended entries are present.
getfacl /data/shared/report.txtSample lines:
user::rw-
user:alice:r--
group::r--
mask::r--
other::r--A strong answer is:
"POSIX ACLs let me grant per-user or per-group access on one inode without changing owner or opening the file to everyone. On Linux I inspect with getfacl and change with setfacl on ACL-capable filesystems like ext4 and xfs."
What does the ACL mask do?
The mask (mask::) is the ceiling for named users, named groups, and the owning group entry. Even if user:bob:rwx is listed, effective access is the intersection of that entry and the mask.
getfacl -e /data/fileWhen the mask is tight you may see:
user:bob:rwx #effective:r--
mask::r--That #effective:r-- line is what the kernel actually enforces. Fix it by raising the mask (setfacl -m m::rwx) or by letting setfacl recalculate the mask (omit -n).
A strong answer is:
"The mask caps effective rights for named users, named groups, and the owning group — I use getfacl -e to see effective permissions when access looks wrong despite a permissive user line."
What is the difference between access ACL and default ACL?
An access ACL applies to the file or directory itself — who can read, write, or traverse it right now.
A default ACL exists only on directories. It does not change existing files; it tells the kernel which ACL entries to copy onto new files and subdirectories created inside.
sudo setfacl -m u:alice:r-x -d -m u:alice:r-- /data/shared
getfacl /data/sharedLook for lines starting with default: in getfacl output. Missing defaults are why a user can access the folder but not files created by someone else.
A strong answer is:
"Access ACL controls the object itself; default ACL on a directory defines inheritance for new children only — I set both when building a team folder on ext4 or xfs."
When do you use setfacl vs chacl?
setfacl is for everyday administration: add one user (-m), remove one entry (-x), strip everything (-b), or set directory defaults (-d). Each call changes only what you specify.
chacl replaces the entire ACL from a single rule string — closer to a reset or generated policy. A second chacl run does not merge; it overwrites again.
| Task | Tool |
|---|---|
| Grant one user read | setfacl -m u:alice:r-- file |
| Remove one user | setfacl -x u:alice file |
| Declarative full ACL | chacl "u::rw-,g::r--,o::---" file |
| Strip extended ACLs | setfacl -b or chacl -B |
A strong answer is:
"I use setfacl for incremental ACL edits and chacl only when I need to replace the whole ACL or reset to a known template — chacl is not safe for small tweaks."
Does Linux chmod support +a for ACLs?
No on GNU/Linux. chmod +a is macOS/BSD syntax for attaching ACL rules. Linux distributions ship POSIX ACL tools in the acl package instead.
chmod +aOn Ubuntu 25.04 that fails — there is no +a operand. The portable Linux equivalent is:
sudo setfacl -m u:alice:r-- /path/to/file
getfacl /path/to/fileKeep using chmod for u+rw, g+r, and numeric modes; use setfacl when you need a named principal.
A strong answer is:
"GNU chmod on Linux does not implement chmod +a — that is BSD/macOS. I use setfacl -m for per-user ACL entries and getfacl to verify them on ext4 or xfs."
Do ACLs work on ext4 and xfs?
Yes, when the filesystem is mounted with ACL support — default on Ubuntu for both ext4 and xfs.
Check ext4 mount options:
tune2fs -l /dev/ROOT_DEVICE | grep "Default mount options"You should see acl in the list. On xfs, ACLs are part of the standard feature set. tmpfs and other filesystems may lack ACL support; setfacl then fails with Operation not supported.
A strong answer is:
"ext4 and xfs on Ubuntu support POSIX ACLs out of the box — I confirm with tune2fs or mount options if setfacl returns operation not supported."
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Operation not supported |
Filesystem or mount without ACL | Use ext4/xfs; check mount for noacl |
User still denied after setfacl -m u:user:rwx |
Mask too restrictive | getfacl -e FILE; raise mask with setfacl -m m::rwx |
+ in ls -l but no extra users listed |
Leftover mask or empty extended set | setfacl -b FILE to clear extended ACL |
| New files lack expected ACL | No default ACL on parent directory | setfacl -d -m … on the directory |
setfacl: Option -m: Invalid argument |
Bad user/group name | Use getent passwd user / getent group grp |
chmod +a fails on Linux |
BSD-only syntax | Use setfacl -m instead |
chacl removed wanted entries |
Full replace semantics | Use setfacl -m / -x; backup with getfacl -R first |
