Comprehensive reference for managing Linux users, groups, permissions, ACLs, quotas, and authentication policies.
Table of Contents#
- Overview
- User Operations
- UID/GID Ranges and System Users
- Login Shells
- Group Operations
- Modifying Users
- Querying User Information
- Important Files
- Sudo Configuration
- Access Control Lists (ACLs)
- User Quotas
- PAM Password Policies
- Examples
- Troubleshooting
- Sources
1. Overview#
Linux user management controls who can log in, what they can access, and what privileges they have. The system identifies users by numeric UIDs and groups by GIDs. Authentication, authorization, and account policies are configured through files in /etc/, PAM modules, and tools like sudo. Understanding the full stack, from user creation to ACLs and quotas, is essential for system administration and security.
2. User Operations#
| Command | Description |
|---|---|
sudo adduser <username> | Create a new user (interactive, Debian-style) |
sudo useradd <username> | Create a new user (low-level, all distros) |
sudo useradd -m -s /bin/bash <username> | Create user with home directory and shell |
sudo userdel <username> | Delete a user (keeps home directory) |
sudo userdel -r <username> | Delete a user and their home directory |
sudo passwd <username> | Set or change a user's password |
sudo chage -l <username> | View password aging information |
sudo chage -M 90 <username> | Set maximum password age to 90 days |
sudo chage -d 0 <username> | Force password change on next login |
3. UID/GID Ranges and System Users#
Linux reserves specific UID/GID ranges by convention (defined in /etc/login.defs):
| Range | Type | Purpose |
|---|---|---|
| 0 | root | Superuser |
| 1-999 | System accounts | Daemons, services (no login, no home directory) |
| 1000-60000 | Regular users | Human users (default UID_MIN/UID_MAX on most distros) |
| 65534 | nobody | Unprivileged fallback user for NFS, etc. |
Key settings in /etc/login.defs:
UID_MIN 1000
UID_MAX 60000
SYS_UID_MIN 201
SYS_UID_MAX 999
GID_MIN 1000
GID_MAX 60000Creating system users:
# Create a system user (UID below 1000, no home, no login)
sudo useradd -r -s /usr/sbin/nologin <service-name>
# Create a system user with a specific home directory
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/<service-name> -m <service-name>
# Verify the assigned UID
id <service-name>4. Login Shells#
The login shell determines what happens when a user logs in. Non-interactive accounts should use a restricted shell:
| Shell | Purpose |
|---|---|
/bin/bash | Standard interactive shell |
/bin/zsh | Z shell (interactive) |
/bin/fish | Fish shell (interactive) |
/usr/sbin/nologin | Politely denies login with a message; preferred for service accounts |
/bin/false | Silently denies login (exits with status 1); older convention |
/usr/bin/git-shell | Allows only git push/pull operations (for git-only SSH accounts) |
# Set a user's shell to nologin (disable interactive login)
sudo usermod -s /usr/sbin/nologin <username>
# List valid shells
cat /etc/shells
# Change your own shell
chsh -s /bin/zshSecurity note: service accounts should always use /usr/sbin/nologin or /bin/false. An interactive shell on a service account is a privilege escalation vector if the account is compromised.
5. Group Operations#
| Command | Description |
|---|---|
sudo groupadd <groupname> | Create a new group |
sudo groupadd -g <gid> <groupname> | Create a group with a specific GID |
sudo groupdel <groupname> | Delete a group |
sudo usermod -aG <groupname> <username> | Add a user to a group (append; -a is critical) |
sudo gpasswd -d <username> <groupname> | Remove a user from a group |
groups <username> | Show groups a user belongs to |
getent group <groupname> | Show members of a group |
newgrp <groupname> | Switch primary group for current session |
Warning: omitting -a with -G replaces all supplementary groups with only the one specified.
6. Modifying Users#
| Command | Description |
|---|---|
sudo usermod -l <newname> <oldname> | Rename a user |
sudo usermod -d /new/home -m <username> | Change home directory and move files |
sudo usermod -s /bin/zsh <username> | Change the default shell |
sudo usermod -L <username> | Lock a user account (prefix ! to password hash) |
sudo usermod -U <username> | Unlock a user account |
sudo usermod -e 2026-12-31 <username> | Set account expiry date |
sudo usermod -u <new-uid> <username> | Change UID (update file ownership separately) |
sudo usermod -g <new-gid> <username> | Change primary group |
After changing a UID, fix file ownership:
sudo find / -user <old-uid> -exec chown <new-uid> {} +7. Querying User Information#
id <username> # Show UID, GID, and groups
whoami # Show current user
who # Show logged-in users
w # Show logged-in users with activity
last # Show login history
last <username> # Show login history for a specific user
lastlog # Show last login of all users
faillog -a # Show failed login attempts
getent passwd <username> # Query user from all NSS sources (LDAP, local, etc.)8. Important Files#
| File | Description |
|---|---|
/etc/passwd | User account information (name, UID, GID, home, shell) |
/etc/shadow | Encrypted passwords and aging data (restricted access) |
/etc/group | Group definitions (name, GID, member list) |
/etc/gshadow | Group passwords (rarely used) |
/etc/login.defs | Default settings for user creation (UID/GID ranges, password policies) |
/etc/skel/ | Template for new user home directories |
/etc/sudoers | Sudo authorization policy |
/etc/sudoers.d/ | Drop-in directory for modular sudo rules |
/etc/security/limits.conf | Per-user resource limits (PAM) |
/etc/pam.d/ | PAM module configuration files |
Format of /etc/passwd:
username:x:UID:GID:comment:home:shellFormat of /etc/shadow:
username:$hash:last_change:min:max:warn:inactive:expire:reserved9. Sudo Configuration#
Basics#
# Add user to sudo/wheel group
sudo usermod -aG sudo <username> # Debian/Ubuntu
sudo usermod -aG wheel <username> # RHEL/Fedora/Arch
# Add a sudoers drop-in file (safer than editing /etc/sudoers directly)
echo "<username> ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/<username>
sudo chmod 440 /etc/sudoers.d/<username>Sudoers Syntax#
Always edit with visudo to prevent syntax errors that lock you out:
sudo visudo # edit /etc/sudoers
sudo visudo -f /etc/sudoers.d/myfile # edit a drop-in fileSudoers rule format:
<who> <where>=(<runas>) <commands>| Field | Description |
|---|---|
<who> | User or %group |
<where> | Hostname (usually ALL) |
<runas> | User to run as (usually ALL or root) |
<commands> | Comma-separated command paths, or ALL |
Examples:
# Allow user full sudo with password
alice ALL=(ALL) ALL
# Allow group without password
%devops ALL=(ALL) NOPASSWD: ALL
# Allow specific commands only
bob ALL=(root) /usr/bin/systemctl restart nginx, /usr/bin/journalctl
# Allow a user to run commands as another user
deploy ALL=(www-data) NOPASSWD: /usr/bin/rsync
# Require password, but cache for 30 minutes
Defaults:alice timestamp_timeout=30
# Log all sudo commands to a file
Defaults logfile="/var/log/sudo.log"Sudo Security#
| Setting | Description |
|---|---|
Defaults requiretty | Require a TTY for sudo (blocks cron/scripts) |
Defaults passwd_tries=3 | Limit password attempts |
Defaults secure_path="/usr/local/sbin:..." | Override PATH for sudo commands |
Defaults !root_sudo | Prevent root from using sudo |
Defaults lecture="always" | Always show the "be careful" lecture |
10. Access Control Lists (ACLs)#
Standard Unix permissions (owner/group/other) only support one owner and one group. ACLs provide fine-grained control for multiple users and groups.
Prerequisites: filesystem must be mounted with ACL support (ext4 has it by default; XFS always supports it).
Viewing ACLs#
# Show ACLs for a file
getfacl <file>
# Show ACLs for a directory
getfacl <directory>Setting ACLs#
# Grant a specific user read/write
setfacl -m u:<username>:rw <file>
# Grant a specific group read-only
setfacl -m g:<groupname>:r <file>
# Set default ACL on a directory (inherited by new files)
setfacl -d -m u:<username>:rwx <directory>
# Remove a specific ACL entry
setfacl -x u:<username> <file>
# Remove all ACLs (revert to standard permissions)
setfacl -b <file>
# Copy ACLs from one file to another
getfacl <source> | setfacl --set-file=- <target>
# Recursive ACL application
setfacl -R -m g:<groupname>:rx <directory>ACL Mask#
The mask defines the maximum effective permissions for named users and groups:
# Set the mask (limits effective permissions)
setfacl -m m::rx <file>
# After setting: a user with rw ACL effectively gets only rxACL Indicators#
When ACLs are present, ls -l shows a + after the permission bits:
-rw-rwxr--+ 1 alice devs 4096 Mar 22 10:00 report.txt11. User Quotas#
Quotas limit disk usage per user or group, preventing any single user from filling a filesystem.
Setup#
# Install quota tools
sudo apt install quota # Debian/Ubuntu
sudo pacman -S quota-tools # Arch
# Enable quotas in /etc/fstab (add usrquota,grpquota to options)
# /dev/sda1 /home ext4 defaults,usrquota,grpquota 0 2
# Remount the filesystem
sudo mount -o remount /home
# Initialize quota database
sudo quotacheck -cugm /home
# Enable quotas
sudo quotaon /homeManaging Quotas#
# Edit quotas for a user (opens editor)
sudo edquota <username>
# Set quotas directly (soft=500M, hard=1G, inodes soft=10000, hard=15000)
sudo setquota -u <username> 500M 1G 10000 15000 /home
# Copy quotas from one user to another
sudo edquota -p <template-user> <target-user>
# View quota for a user
quota -u <username>
# View quota report for all users
sudo repquota -a
# Set a grace period for soft limits
sudo edquota -tQuota Concepts#
| Concept | Description |
|---|---|
| Soft limit | Threshold that can be exceeded temporarily (grace period) |
| Hard limit | Absolute maximum; writes fail beyond this |
| Grace period | Time a user can exceed the soft limit before it becomes enforced |
| Block quota | Limits total disk space (in KB or MB) |
| Inode quota | Limits the number of files (each file uses one inode) |
12. PAM Password Policies#
PAM (Pluggable Authentication Modules) enforces password complexity, lockout, and other policies.
Password Quality (pam_pwquality)#
Configuration in /etc/security/pwquality.conf or as PAM module arguments:
# Minimum password length
minlen = 12
# Require at least 1 uppercase, 1 lowercase, 1 digit, 1 special
ucredit = -1
lcredit = -1
dcredit = -1
ocredit = -1
# Reject passwords containing the username
usercheck = 1
# Reject dictionary words
dictcheck = 1
# Maximum consecutive identical characters
maxrepeat = 3
# Minimum number of character classes (uppercase, lowercase, digit, other)
minclass = 3
# Reject passwords similar to the old one
difok = 5PAM configuration (typically in /etc/pam.d/common-password or /etc/pam.d/system-auth):
password requisite pam_pwquality.so retry=3 enforce_for_root
password required pam_unix.so use_authtok sha512 shadowAccount Lockout (pam_faillock)#
# /etc/security/faillock.conf (modern method)
deny = 5 # lock after 5 failed attempts
unlock_time = 600 # unlock after 600 seconds (10 minutes)
fail_interval = 900 # count failures within 15 minutes
# PAM configuration
auth required pam_faillock.so preauth
auth required pam_faillock.so authfail
account required pam_faillock.so# View failed login attempts
faillock --user <username>
# Manually unlock a locked account
faillock --user <username> --resetPassword History (pam_pwhistory)#
Prevent users from reusing recent passwords:
# In /etc/pam.d/common-password or system-auth
password required pam_pwhistory.so remember=12 enforce_for_root use_authtok13. Examples#
Create a System User for a Service#
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/myapp -m myappBulk Add Users from a File#
while IFS=: read -r user pass; do
sudo useradd -m "$user"
echo "$user:$pass" | sudo chpasswd
done < users.txtGrant Sudo Privileges#
# Add user to sudo/wheel group
sudo usermod -aG sudo <username> # Debian/Ubuntu
sudo usermod -aG wheel <username> # RHEL/Fedora/Arch
# Or add a sudoers entry (use visudo or drop-in file)
echo "<username> ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/<username>
sudo chmod 440 /etc/sudoers.d/<username>Set Up a Shared Directory with ACLs#
# Create the shared directory
sudo mkdir /srv/shared
sudo chown root:devteam /srv/shared
sudo chmod 2770 /srv/shared # setgid ensures new files inherit group
# Grant additional access to another group
setfacl -m g:managers:rx /srv/shared
setfacl -d -m g:managers:rx /srv/shared # default ACL for new filesAudit User Accounts#
# Find users with UID 0 (should only be root)
awk -F: '$3 == 0 {print $1}' /etc/passwd
# Find users with empty passwords
sudo awk -F: '$2 == "" {print $1}' /etc/shadow
# Find users with no expiry set
sudo chage -l <username> | grep "Account expires"
# Find accounts that have never logged in
lastlog | grep "**Never logged in**"Troubleshooting#
| Issue | Cause | Solution |
|---|---|---|
useradd creates user without home directory | Missing -m flag (behavior varies by distro) | Use useradd -m or set CREATE_HOME yes in /etc/login.defs |
| User cannot sudo | Not in sudo/wheel group | usermod -aG sudo <user> (Debian) or wheel (RHEL/Arch); user must log out and back in |
usermod -G removed all other groups | Missing -a (append) flag | Always use -aG together; re-add removed groups |
| ACLs not working | Filesystem mounted without ACL support | Remount with acl option or check if the filesystem supports ACLs natively |
| Quota not enforced | Quota not enabled or database not initialized | Run quotacheck -cugm and quotaon on the filesystem |
| Password change rejected | PAM policy too strict | Check /etc/security/pwquality.conf; adjust minlen, credits, or difok |
| Account locked after failed logins | pam_faillock triggered | Unlock with faillock --user <user> --reset |
| New user cannot log in via SSH | Shell set to /usr/sbin/nologin or not listed in /etc/shells | Verify shell with getent passwd <user> and check /etc/shells |
Sources#
man useradd,man usermod,man userdelman passwd,man shadow,man chageman sudoers,man visudoman setfacl,man getfaclman edquota,man repquotaman pam_pwquality,man pam_faillock,man pam_pwhistory