Mastering the usermod Command: A Complete Guide to Linux User Account Modification
Introduction
User management is a cornerstone of Linux system administration. While creating and deleting accounts are important operations, the reality of system administration involves constant change—users change departments, need additional permissions, require home directory moves, or need their shells updated for new workflows. This is where usermod becomes an indispensable tool.
The usermod command is the standard utility for modifying existing user accounts on Linux systems. It allows administrators to change nearly every aspect of a user account—from basic attributes like the home directory and shell to complex configurations like group memberships, password aging, and SELinux contexts. Whether you’re renaming a user, locking an account for security, or migrating a user’s home to a new disk, usermod provides the flexibility you need.
Unlike manually editing /etc/passwd or /etc/shadow, usermod ensures data integrity, maintains proper file locking to prevent corruption, and handles the complex interdependencies between user attributes. It also updates related system files like /etc/group and /etc/gshadow automatically.
This comprehensive tutorial will guide you through everything you need to know about usermod, from basic attribute changes to advanced scenarios, with practical examples and safety best practices.
Understanding usermod and Its Place in User Management
Before diving into the command itself, let’s understand how usermod fits into the broader landscape of Linux user management tools:
flowchart TB
subgraph UserLifecycle["Linux User Account Lifecycle"]
direction TB
subgraph Creation["Creation Phase"]
C1[useradd] --> C2[Create account]
C3[passwd] --> C4[Set credentials]
end
subgraph Active["Active Management"]
M1[usermod] --> M2[Modify attributes]
M3[chage] --> M4[Password policies]
M5[passwd] --> M6[Change password]
end
subgraph Deletion["Deletion Phase"]
D1[userdel] --> D2[Remove account]
end
end
C2 --> M2
M2 --> D2
style Creation fill:#99ff99,stroke:#333
style Active fill:#99ccff,stroke:#333
style Deletion fill:#ffcc99,stroke:#333
What usermod Modifies
The usermod command can modify these account attributes:
| File | Attributes Modified |
|---|---|
/etc/passwd | Username, UID, GID, home directory, shell, GECOS info |
/etc/shadow | Password status, aging policies, account expiration |
/etc/group | Supplementary group memberships |
/etc/gshadow | Group administrator/member information |
/etc/subuid | Subordinate UID ranges (user namespaces) |
/etc/subgid | Subordinate GID ranges (user namespaces) |
Key Characteristics of usermod
| Feature | Description | Benefit |
|---|---|---|
| Atomic Updates | Locks files during modification | Prevents corruption |
| Validation | Checks for conflicts and invalid values | Prevents system errors |
| File Operations | Can move home directories automatically | Simplifies migrations |
| Group Management | Handles primary and supplementary groups | Flexible permission control |
| Security Controls | Locks, expires, and restricts accounts | Enhanced security |
usermod vs. Related Commands
| Command | Purpose | When to Use |
|---|---|---|
| usermod | Modify existing users | Changing any user attribute |
| useradd | Create new users | Initial account creation |
| userdel | Delete users | Account removal |
| chage | Password aging only | Fine-tuned password policy |
| passwd | Password changes | Credential management |
| gpasswd | Group management | Adding/removing group members |
Basic Syntax and Usage
Command Structure
usermod [options] LOGIN
Simplest Usage
# Add user to a supplementary group
usermod -aG developers username
# Change user's home directory
usermod -d /new/home username
# Lock a user account
usermod -L username
# Change user's shell
usermod -s /bin/zsh username
How usermod Works
flowchart LR
A[usermod command] --> B{User exists?}
B -->|No| C[Error: user does not exist]
B -->|Yes| D{Validate options}
D -->|Invalid| E[Error: invalid parameters]
D -->|Valid| F[Lock system files]
F --> G[Apply changes to /etc/passwd]
G --> H[Apply changes to /etc/shadow]
H --> I[Update /etc/group if needed]
I --> J[Execute file operations]
J --> K[Unlock system files]
K --> L[Complete]
style A fill:#99ccff,stroke:#333
style L fill:#99ff99,stroke:#333
style C fill:#ff9999,stroke:#333
style E fill:#ff9999,stroke:#333
Important Safety Notes
- User must exist:
usermodcannot create users—only modify existing ones - Logged-in users: Some changes (like UID) require the user to be logged out
- Backup first: Major changes like UID or home directory moves should be preceded by backups
- Group append: Use
-awith-Gto append to groups; without-a, groups are replaced
Command-Line Options Reference
Complete Option Reference Table
| Option | Long Option | Description | Example |
|---|---|---|---|
-a | --append | Append to supplementary groups (use with -G) | usermod -aG group user |
-b | --badnames | Allow bad names | usermod -b username |
-c | --comment | GECOS field (full name, phone, etc.) | usermod -c "John Doe" user |
-d | --home | Home directory | usermod -d /new/home user |
-e | --expiredate | Account expiration date (YYYY-MM-DD) | usermod -e 2024-12-31 user |
-f | --inactive | Password inactive days | usermod -f 7 user |
-g | --gid | Primary group (GID or name) | usermod -g developers user |
-G | --groups | Supplementary groups | usermod -G group1,group2 user |
-h | --help | Display help | usermod --help |
-l | --login | New username (login) | usermod -l newname oldname |
-L | --lock | Lock password | usermod -L user |
-m | --move-home | Move home directory contents | usermod -m -d /new/home user |
-o | --non-unique | Allow duplicate UID | usermod -o -u 1000 user |
-p | --password | Encrypted password (avoid) | usermod -p encrypted user |
-R | --root | Chroot into directory | usermod -R /mnt user |
-s | --shell | Login shell | usermod -s /bin/bash user |
-u | --uid | User ID (UID) | usermod -u 2000 user |
-U | --unlock | Unlock password | usermod -U user |
-v | --add-subuids | Add subordinate UIDs | usermod -v 100000-165535 user |
-V | --del-subuids | Remove subordinate UIDs | usermod -V 100000-165535 user |
-w | --add-subgids | Add subordinate GIDs | usermod -w 100000-165535 user |
-W | --del-subgids | Remove subordinate GIDs | usermod -W 100000-165535 user |
-Z | --selinux-user | SELinux user mapping | usermod -Z user_u user |
Practical Examples
1. Changing User Information (GECOS Field)
The GECOS field stores additional user information:
# Set full name
usermod -c "John Smith" jsmith
# Set full name with additional info (comma-separated)
# Format: Full Name,Room Number,Work Phone,Home Phone,Other
usermod -c "Jane Doe,101,555-1234,555-5678,Engineering" jdoe
# View current GECOS info
getent passwd jsmith
# Output: jsmith:x:1000:1000:John Smith:/home/jsmith:/bin/bash
# Use chfn for interactive editing
chfn jsmith
2. Managing Group Memberships
# Add user to supplementary groups (replaces existing!)
usermod -G developers,operators,docker jsmith
# Append user to additional groups (safer)
usermod -aG developers jsmith
# Add to multiple groups at once
usermod -aG wheel,sudo,admins jsmith
# Change primary group
usermod -g developers jsmith
# Remove from all supplementary groups
usermod -G "" jsmith
# View current groups
groups jsmith
id jsmith
Important: Without -a, the -G option replaces all supplementary groups. Always use -aG to add groups safely.
3. Locking and Unlocking Accounts
# Lock account (prevent login)
usermod -L jsmith
# Verify lock status
passwd -S jsmith
# LK = Locked, PS = Password set, NP = No password
# Unlock account
usermod -U jsmith
# Alternative methods
passwd -l jsmith # Lock
passwd -u jsmith # Unlock
4. Changing Home Directory
# Change home directory path only (doesn't move files)
usermod -d /data/users/jsmith jsmith
# Change home directory and move contents
usermod -m -d /data/users/jsmith jsmith
# Create new home manually, then update
mkdir /newhome/jsmith
chown jsmith:jsmith /newhome/jsmith
chmod 700 /newhome/jsmith
cp -r /home/jsmith/. /newhome/jsmith/
usermod -d /newhome/jsmith jsmith
5. Changing User Shell
# Change to Zsh
usermod -s /bin/zsh jsmith
# Change to Bash
usermod -s /bin/bash jsmith
# Restrict to rbash (restricted bash)
usermod -s /bin/rbash jsmith
# Disable interactive login (service accounts)
usermod -s /sbin/nologin serviceaccount
# View available shells
cat /etc/shells
# Verify change
grep jsmith /etc/passwd
6. Setting Account Expiration
# Set account expiration date
usermod -e 2024-12-31 jsmith
# Set expiration to never
usermod -e "" jsmith
# View expiration info
chage -l jsmith
# Check using passwd
passwd -S jsmith
# Common use case: Temporary contractor account
useradd contractor1
usermod -e $(date -d "+90 days" +%Y-%m-%d) contractor1
7. Changing Username (Login)
# Rename user from jsmith to johnsmith
usermod -l johnsmith jsmith
# Note: This does NOT rename the home directory
# Home directory is still /home/jsmith
# Rename user AND home directory
usermod -l johnsmith -m -d /home/johnsmith jsmith
# Update email/mail spool (manual step)
mv /var/mail/jsmith /var/mail/johnsmith 2>/dev/null || true
# Verify changes
id johnsmith
getent passwd johnsmith
8. Changing UID
# Change UID from 1000 to 2000
usermod -u 2000 jsmith
# Important: Files owned by old UID are not automatically updated
# Find and fix ownership
find / -uid 1000 -exec chown 2000 {} \; 2>/dev/null
# Better approach: Use find with user's home and common locations
find /home/jsmith /var/mail /tmp -uid 1000 -exec chown jsmith {} \; 2>/dev/null
# Allow duplicate UID (rarely needed)
usermod -o -u 0 backupadmin # Creates second UID 0 user
Warning: Changing UID while user is logged in can cause issues. Ensure user is logged out first.
9. Password Aging and Inactivity
# Set password inactive days (days after expiry before lock)
usermod -f 7 jsmith
# View password aging
chage -l jsmith
# Using chage for more control (recommended)
chage -M 90 jsmith # Max password age: 90 days
chage -m 7 jsmith # Min password age: 7 days
chage -W 14 jsmith # Warning 14 days before expiry
10. Comprehensive User Update Script
#!/bin/bash
# update-user.sh - Comprehensive user modification
USERNAME=$1
shift
show_usage() {
echo "Usage: $0 <username> [options]"
echo ""
echo "Options:"
echo " --name 'Full Name' Set GECOS name"
echo " --home /new/home Change home directory"
echo " --move-home Move home directory contents"
echo " --shell /bin/shell Change login shell"
echo " --add-group group Add to group"
echo " --primary-group group Set primary group"
echo " --lock Lock account"
echo " --unlock Unlock account"
echo " --expire YYYY-MM-DD Set expiration date"
echo " --rename newname Rename user"
echo ""
echo "Example:"
echo " $0 jsmith --name 'John Smith' --add-group docker --shell /bin/zsh"
}
if [ -z "$USERNAME" ]; then
show_usage
exit 1
fi
# Check if user exists
if ! id "$USERNAME" &>/dev/null; then
echo "Error: User $USERNAME does not exist"
exit 1
fi
# Process arguments
while [[ $# -gt 0 ]]; do
case $1 in
--name)
usermod -c "$2" "$USERNAME"
echo "Updated GECOS name to: $2"
shift 2
;;
--home)
NEW_HOME="$2"
shift 2
;;
--move-home)
MOVE_HOME=1
shift
;;
--shell)
usermod -s "$2" "$USERNAME"
echo "Updated shell to: $2"
shift 2
;;
--add-group)
usermod -aG "$2" "$USERNAME"
echo "Added to group: $2"
shift 2
;;
--primary-group)
usermod -g "$2" "$USERNAME"
echo "Set primary group to: $2"
shift 2
;;
--lock)
usermod -L "$USERNAME"
echo "Account locked"
shift
;;
--unlock)
usermod -U "$USERNAME"
echo "Account unlocked"
shift
;;
--expire)
usermod -e "$2" "$USERNAME"
echo "Account expires on: $2"
shift 2
;;
--rename)
NEW_NAME="$2"
shift 2
;;
*)
echo "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Handle home directory change with optional move
if [ -n "$NEW_HOME" ]; then
if [ "$MOVE_HOME" = 1 ]; then
usermod -m -d "$NEW_HOME" "$USERNAME"
echo "Moved home directory to: $NEW_HOME"
else
usermod -d "$NEW_HOME" "$USERNAME"
echo "Updated home directory to: $NEW_HOME (files not moved)"
fi
fi
# Handle rename
if [ -n "$NEW_NAME" ]; then
usermod -l "$NEW_NAME" "$USERNAME"
echo "User renamed from $USERNAME to $NEW_NAME"
fi
echo ""
echo "Updated user information:"
id "${NEW_NAME:-$USERNAME}"
Advanced Usage Scenarios
System Administration Scripts
Bulk Group Assignment
#!/bin/bash
# bulk-group-assign.sh - Add multiple users to a group
TARGET_GROUP=$1
shift
if [ -z "$TARGET_GROUP" ] || [ $# -eq 0 ]; then
echo "Usage: $0 <group> <user1> [user2] [user3] ..."
exit 1
fi
# Check if group exists
if ! getent group "$TARGET_GROUP" > /dev/null; then
echo "Error: Group $TARGET_GROUP does not exist"
exit 1
fi
for user in "$@"; do
if id "$user" &>/dev/null; then
if usermod -aG "$TARGET_GROUP" "$user"; then
echo "✓ Added $user to $TARGET_GROUP"
else
echo "✗ Failed to add $user"
fi
else
echo "✗ User $user does not exist"
fi
done
echo ""
echo "Group membership updated:"
getent group "$TARGET_GROUP"
Home Directory Migration
#!/bin/bash
# migrate-homes.sh - Migrate user homes to new storage
NEW_BASE="/data/home"
LOG_FILE="/var/log/home-migration.log"
mkdir -p "$NEW_BASE"
exec 1> >(tee -a "$LOG_FILE")
exec 2>&1
echo "=== Home Directory Migration Started: $(date) ==="
# Process all regular users (UID >= 1000)
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $6}' /etc/passwd | while read -r user home; do
# Skip if already in new location
if [[ "$home" == "$NEW_BASE"* ]]; then
echo "Skipping $user - already migrated"
continue
fi
new_home="$NEW_BASE/$user"
echo "Migrating $user: $home -> $new_home"
# Create new home
mkdir -p "$new_home"
# Copy data
if [ -d "$home" ]; then
cp -a "$home/." "$new_home/" 2>/dev/null || true
fi
# Set ownership
chown -R "$user:$user" "$new_home"
chmod 700 "$new_home"
# Update usermod
if usermod -m -d "$new_home" "$user"; then
echo " ✓ Migration successful"
# Backup and remove old home (optional)
# mv "$home" "$home.backup.$(date +%Y%m%d)"
else
echo " ✗ Migration failed"
fi
done
echo "=== Migration Completed: $(date) ==="
Account Lifecycle Management
#!/bin/bash
# account-lifecycle.sh - Manage account states
USERNAME=$1
ACTION=$2
case "$ACTION" in
suspend)
echo "Suspending account: $USERNAME"
usermod -L "$USERNAME"
usermod --expiredate 1 "$USERNAME"
pkill -u "$USERNAME" 2>/dev/null || true
echo "Account suspended"
;;
resume)
echo "Resuming account: $USERNAME"
usermod -U "$USERNAME"
usermod --expiredate "" "$USERNAME"
echo "Account resumed"
;;
vacation)
echo "Setting vacation mode: $USERNAME"
usermod -L "$USERNAME"
usermod -e $(date -d "+14 days" +%Y-%m-%d) "$USERNAME"
echo "Account locked for 14 days"
;;
extend)
DAYS=${3:-30}
echo "Extending account: $USERNAME by $DAYS days"
usermod -e $(date -d "+$DAYS days" +%Y-%m-%d) "$USERNAME"
echo "Account extended"
;;
*)
echo "Usage: $0 <username> <suspend|resume|vacation|extend [days]>"
exit 1
;;
esac
Development and Testing
Test User Generator
#!/bin/bash
# generate-test-users.sh - Create test users with specific configurations
PREFIX=${1:-test}
COUNT=${2:-5}
for i in $(seq 1 $COUNT); do
username="${PREFIX}${i}"
# Create user if doesn't exist
if ! id "$username" &>/dev/null; then
useradd -m "$username"
fi
# Configure for testing
usermod -s /bin/bash "$username"
usermod -aG docker,developers "$username"
usermod -e $(date -d "+7 days" +%Y-%m-%d) "$username"
usermod -c "Test User $i" "$username"
# Set temporary password
echo "$username:temp123" | chpasswd
echo "Created: $username"
done
echo ""
echo "Test users created. They will expire in 7 days."
Permission Testing Setup
#!/bin/bash
# setup-perm-test.sh - Create users for permission testing
# Create test users with different group configurations
useradd -m user_no_groups
useradd -m user_one_group
useradd -m user_many_groups
# Setup different group scenarios
usermod -G "" user_no_groups # No supplementary groups
usermod -G developers user_one_group # One group
usermod -G developers,operators,qa,docker user_many_groups # Many groups
# Set shells for different test scenarios
usermod -s /bin/bash user_no_groups
usermod -s /bin/sh user_one_group
usermod -s /bin/zsh user_many_groups
echo "Test users created:"
id user_no_groups
id user_one_group
id user_many_groups
Container and Namespace Management
Subordinate UID/GID Management
#!/bin/bash
# setup-container-user.sh - Configure user for rootless containers
USERNAME=$1
if [ -z "$USERNAME" ]; then
echo "Usage: $0 <username>"
exit 1
fi
# Check if user exists
if ! id "$USERNAME" &>/dev/null; then
echo "Creating user: $USERNAME"
useradd -m "$USERNAME"
fi
# Get current UID
USER_UID=$(id -u "$USERNAME")
# Calculate subordinate range (common pattern)
SUBUID_START=$((100000 + USER_UID * 65536))
SUBUID_END=$((SUBUID_START + 65535))
# Add subordinate UIDs
usermod -v "${SUBUID_START}-${SUBUID_END}" "$USERNAME"
# Add subordinate GIDs
usermod -w "${SUBUID_START}-${SUBUID_END}" "$USERNAME"
echo "Configured subordinate IDs for $USERNAME:"
echo " UID range: $SUBUID_START-$SUBUID_END"
grep "^$USERNAME:" /etc/subuid /etc/subgid
Best Practices and Safety Guidelines
1. Always Use Append for Groups
# BAD: Replaces all supplementary groups!
usermod -G docker jsmith
# User is now ONLY in docker group
# GOOD: Appends to existing groups
usermod -aG docker jsmith
# User added to docker, keeps existing groups
# Verify current groups before and after
groups jsmith
id jsmith
2. Backup Before Major Changes
#!/bin/bash
# safe-usermod.sh - Safe wrapper for major changes
USERNAME=$1
# Backup user data
backup_user() {
local user=$1
local backup_dir="/backup/users/$(date +%Y%m%d)"
mkdir -p "$backup_dir"
# Backup passwd/shadow entries
grep "^$user:" /etc/passwd > "$backup_dir/${user}.passwd"
grep "^$user:" /etc/shadow > "$backup_dir/${user}.shadow"
# Backup group memberships
groups "$user" > "$backup_dir/${user}.groups" 2>/dev/null
# Backup home directory
if [ -d "/home/$user" ]; then
tar czf "$backup_dir/${user}-home.tar.gz" -C / "home/$user"
fi
echo "Backup created in: $backup_dir"
}
# Verify user not logged in for UID changes
check_logged_in() {
local user=$1
if who | grep -q "^$user "; then
echo "WARNING: User $user is currently logged in!"
echo "Active sessions:"
who | grep "^$user "
return 1
fi
return 0
}
3. Verify Changes After Application
#!/bin/bash
# verify-usermod.sh - Verify user modifications
USERNAME=$1
echo "Verifying user: $USERNAME"
echo "========================================"
# Check existence
if ! id "$USERNAME" &>/dev/null; then
echo "ERROR: User does not exist"
exit 1
fi
# Display all attributes
echo "UID: $(id -u $USERNAME)"
echo "Primary GID: $(id -g $USERNAME)"
echo "Groups: $(id -Gn $USERNAME)"
echo "Home: $(getent passwd $USERNAME | cut -d: -f6)"
echo "Shell: $(getent passwd $USERNAME | cut -d: -f7)"
echo "GECOS: $(getent passwd $USERNAME | cut -d: -f5)"
echo ""
echo "Password status:"
passwd -S "$USERNAME"
echo ""
echo "Account aging:"
chage -l "$USERNAME"
4. Handle UID Changes Carefully
#!/bin/bash
# change-uid-safe.sh - Safely change user UID
USERNAME=$1
NEW_UID=$2
if [ $# -ne 2 ]; then
echo "Usage: $0 <username> <new-uid>"
exit 1
fi
OLD_UID=$(id -u "$USERNAME")
echo "Changing UID for $USERNAME: $OLD_UID -> $NEW_UID"
# Check if new UID is in use
if id -u "$NEW_UID" &>/dev/null; then
echo "ERROR: UID $NEW_UID is already in use"
exit 1
fi
# Check if user is logged in
if who | grep -q "^$USERNAME "; then
echo "ERROR: User is currently logged in"
exit 1
fi
# Find files owned by old UID
echo "Files owned by old UID:"
find /home /var/mail /tmp -uid "$OLD_UID" 2>/dev/null | head -20
TOTAL_FILES=$(find /home /var/mail /tmp -uid "$OLD_UID" 2>/dev/null | wc -l)
echo "Total files found: $TOTAL_FILES"
read -p "Continue with UID change? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Cancelled"
exit 1
fi
# Change UID
usermod -u "$NEW_UID" "$USERNAME"
# Update file ownership
echo "Updating file ownership..."
find /home /var/mail /tmp -uid "$OLD_UID" -exec chown "$USERNAME" {} \; 2>/dev/null
echo "UID change complete"
id "$USERNAME"
5. Test Changes in Non-Production First
#!/bin/bash
# test-usermod.sh - Test usermod changes on test user
TEST_USER="testuser_$$"
# Create test user
useradd -m "$TEST_USER"
echo "Created test user: $TEST_USER"
# Apply and test changes
echo "Testing group addition..."
usermod -aG docker "$TEST_USER"
groups "$TEST_USER"
echo "Testing shell change..."
usermod -s /bin/zsh "$TEST_USER"
grep "^$TEST_USER:" /etc/passwd | cut -d: -f7
echo "Testing lock/unlock..."
usermod -L "$TEST_USER"
passwd -S "$TEST_USER"
usermod -U "$TEST_USER"
passwd -S "$TEST_USER"
# Cleanup
echo "Cleaning up test user..."
userdel -r "$TEST_USER"
echo "Tests complete"
Comparison with Alternative Commands
usermod vs. vipw/vigr
| Feature | usermod | vipw/vigr |
|---|---|---|
| Safety | Built-in validation and locking | Manual editing risk |
| Atomicity | Single operation | Multiple edits possible |
| Scripting | Excellent | Not suitable |
| Bulk changes | One user at a time | Can edit multiple |
| Learning curve | Command options | Direct file format |
usermod vs. chage
| Task | usermod | chage |
|---|---|---|
| Set expiration date | usermod -e 2024-12-31 user | chage -E 2024-12-31 user |
| Set inactive days | usermod -f 7 user | chage -I 7 user |
| View aging info | Not available | chage -l user |
| Interactive mode | No | Yes (chage user) |
Recommendation: Use chage for password aging, usermod for account attributes.
usermod vs. passwd
| Task | usermod | passwd |
|---|---|---|
| Lock account | usermod -L user | passwd -l user |
| Unlock account | usermod -U user | passwd -u user |
| Change password | usermod -p hash (not recommended) | passwd user |
| Check status | passwd -S user | passwd -S user |
Recommendation: Use passwd for password operations, usermod for account locking.
Troubleshooting Common Issues
Issue: “usermod: user is currently logged in”
# Problem: Cannot change UID or some attributes
$ usermod -u 2000 jsmith
usermod: user jsmith is currently logged in
# Solutions:
# 1. Check logged-in sessions
who | grep jsmith
w | grep jsmith
# 2. Check for processes
ps -u jsmith
# 3. Terminate processes
sudo pkill -u jsmith
# 4. Try again
sudo usermod -u 2000 jsmith
Issue: “usermod: group ‘xxx’ does not exist”
# Problem: Adding to non-existent group
$ usermod -aG developers jsmith
usermod: group 'developers' does not exist
# Solutions:
# 1. Create the group first
groupadd developers
# 2. Check group name spelling
grep -i develop /etc/group
# 3. Use GID if name is problematic
usermod -aG 1005 jsmith
Issue: “usermod: UID already exists”
# Problem: Target UID is taken
$ usermod -u 1000 jsmith
usermod: UID 1000 is already in use
# Solutions:
# 1. Check who has that UID
id 1000
getent passwd 1000
# 2. Choose different UID
usermod -u 2000 jsmith
# 3. Force duplicate UID (dangerous!)
usermod -o -u 1000 jsmith
Issue: Home Directory Move Fails
# Problem: Cannot move home directory
$ usermod -m -d /data/jsmith jsmith
usermod: failed to move home directory
# Solutions:
# 1. Check permissions
ls -ld /data
ls -la /home/jsmith
# 2. Check disk space
df -h /data
df -h /home
# 3. Check for open files
lsof +D /home/jsmith
# 4. Manual move
mkdir -p /data/jsmith
cp -a /home/jsmith/. /data/jsmith/
chown -R jsmith:jsmith /data/jsmith
usermod -d /data/jsmith jsmith
Issue: Changes Not Taking Effect
# Problem: User's new groups not available
$ usermod -aG docker jsmith
$ su - jsmith
$ groups
docker not shown!
# Solutions:
# 1. User must log out and back in
# Group membership is set at login
# 2. Use newgrp for immediate effect
newgrp docker
# 3. Verify with id
id jsmith
Issue: SELinux Context Errors
# Problem: SELinux prevents changes
$ usermod -d /newhome jsmith
usermod: cannot set SELinux context
# Solutions:
# 1. Check SELinux status
getenforce
# 2. Use -Z flag to set context
usermod -Z user_u -d /newhome jsmith
# 3. Relabel files after move
restorecon -Rv /newhome
Real-World Use Cases
System Administration
Contractor Account Management
#!/bin/bash
# manage-contractor.sh - Manage temporary contractor accounts
USERNAME=$1
DAYS=${2:-90}
ACTION=${3:-create}
case "$ACTION" in
create)
useradd -m "$USERNAME"
EXPIRE_DATE=$(date -d "+$DAYS days" +%Y-%m-%d)
usermod -e "$EXPIRE_DATE" "$USERNAME"
usermod -c "Contractor - $USERNAME" "$USERNAME"
usermod -aG contractors,developers "$USERNAME"
echo "Created contractor account: $USERNAME (expires: $EXPIRE_DATE)"
;;
extend)
EXPIRE_DATE=$(date -d "+$DAYS days" +%Y-%m-%d)
usermod -e "$EXPIRE_DATE" "$USERNAME"
echo "Extended $USERNAME to: $EXPIRE_DATE"
;;
revoke)
usermod -L "$USERNAME"
usermod --expiredate 1 "$USERNAME"
pkill -u "$USERNAME" 2>/dev/null || true
echo "Revoked access for: $USERNAME"
;;
*)
echo "Usage: $0 <username> [days] <create|extend|revoke>"
exit 1
;;
esac
Role-Based Access Control Updates
#!/bin/bash
# update-role.sh - Change user role/department
USERNAME=$1
NEW_ROLE=$2
case "$NEW_ROLE" in
developer)
usermod -g developers "$USERNAME"
usermod -G docker,git,build "$USERNAME"
usermod -s /bin/bash "$USERNAME"
;;
ops)
usermod -g operations "$USERNAME"
usermod -G wheel,docker,monitoring "$USERNAME"
usermod -s /bin/bash "$USERNAME"
;;
admin)
usermod -g admin "$USERNAME"
usermod -G wheel,sudo,admins,docker "$USERNAME"
usermod -s /bin/bash "$USERNAME"
;;
service)
usermod -g nogroup "$USERNAME"
usermod -G "" "$USERNAME"
usermod -s /sbin/nologin "$USERNAME"
;;
*)
echo "Unknown role: $NEW_ROLE"
exit 1
;;
esac
echo "Updated $USERNAME to role: $NEW_ROLE"
id "$USERNAME"
Account Deactivation for Leave
#!/bin/bash
# leave-management.sh - Handle employee leave
USERNAME=$1
LEAVE_TYPE=$2 # maternity, paternity, sabbatical, medical
case "$LEAVE_TYPE" in
maternity|paternity)
# 6 months leave
usermod -L "$USERNAME"
usermod -e $(date -d "+180 days" +%Y-%m-%d) "$USERNAME"
usermod -c "$(getent passwd $USERNAME | cut -d: -f5) [On Leave]" "$USERNAME"
pkill -u "$USERNAME" 2>/dev/null || true
echo "$USERNAME on $LEAVE_TYPE leave for 180 days"
;;
sabbatical)
# 1 year leave
usermod -L "$USERNAME"
usermod -e $(date -d "+365 days" +%Y-%m-%d) "$USERNAME"
pkill -u "$USERNAME" 2>/dev/null || true
echo "$USERNAME on sabbatical for 365 days"
;;
medical)
# Indefinite, manual reactivation
usermod -L "$USERNAME"
pkill -u "$USERNAME" 2>/dev/null || true
echo "$USERNAME on medical leave (manual reactivation required)"
;;
return)
# Return from leave
usermod -U "$USERNAME"
usermod -e "" "$USERNAME"
usermod -c "$(getent passwd $USERNAME | cut -d: -f5 | sed 's/ \[On Leave\]//')" "$USERNAME"
echo "$USERNAME returned from leave"
;;
esac
Development Workflows
Development Environment Setup
#!/bin/bash
# setup-dev-env.sh - Configure user for development
USERNAME=$1
if [ -z "$USERNAME" ]; then
echo "Usage: $0 <username>"
exit 1
fi
echo "Setting up development environment for $USERNAME..."
# Add to development groups
usermod -aG docker,developers,git "$USERNAME"
# Set developer-friendly shell
usermod -s /bin/zsh "$USERNAME"
# Create workspace if it doesn't exist
WORKSPACE="/workspace/$USERNAME"
if [ ! -d "$WORKSPACE" ]; then
mkdir -p "$WORKSPACE"
chown "$USERNAME:$USERNAME" "$WORKSPACE"
fi
# Add workspace symlink to home
su - "$USERNAME" -c "ln -sf $WORKSPACE ~/workspace" 2>/dev/null || true
echo "Development environment configured"
echo "Groups: $(groups $USERNAME)"
CI/CD User Configuration
#!/bin/bash
# setup-ci-user.sh - Configure service account for CI/CD
USERNAME="ci-runner"
# Create if doesn't exist
if ! id "$USERNAME" &>/dev/null; then
useradd -m "$USERNAME"
fi
# Configure for CI usage
usermod -s /bin/bash "$USERNAME"
usermod -aG docker,build "$USERNAME"
# Lock password (key auth only)
usermod -L "$USERNAME"
# Set restricted shell options
usermod -c "CI/CD Service Account" "$USERNAME"
# Setup SSH keys
cat > "/home/$USERNAME/.ssh/authorized_keys" << 'EOF'
# Add CI server public keys here
EOF
chown -R "$USERNAME:$USERNAME" "/home/$USERNAME/.ssh"
chmod 700 "/home/$USERNAME/.ssh"
chmod 600 "/home/$USERNAME/.ssh/authorized_keys"
echo "CI user $USERNAME configured"
Frequently Asked Questions
Can I rename a user while they’re logged in?
No, you cannot rename (-l) or change the UID (-u) of a user who is currently logged in. Other changes like groups, shell, and GECOS can typically be made while logged in, but won’t take effect until the next login session.
Why don’t new group memberships work immediately?
Group membership is determined at login time. After adding a user to a group with usermod -aG, the user must either:
- Log out and log back in
- Use
newgrp <groupname>to activate the group in the current session - Start a new shell with
su - username
What’s the difference between primary and supplementary groups?
- Primary group: The main group for the user, used as default for new files. Set with
-g. - Supplementary groups: Additional groups the user belongs to. Set with
-G(use-aGto append).
# View primary group (creates files with this group)
id -gn username
# View all supplementary groups
id -Gn username
Can I change multiple attributes at once?
Yes, combine options in a single command:
usermod -s /bin/zsh -aG docker,developers -c "John Smith" username
How do I move a user’s home to a new disk?
# Create new home location
mkdir /newdisk/username
# Move contents
cp -a /home/username/. /newdisk/username/
chown -R username:username /newdisk/username
# Update and move in one command
usermod -m -d /newdisk/username username
What happens when I lock an account?
Locking with usermod -L prepends a ! to the password hash, preventing password-based login. However:
- SSH key authentication may still work
- Existing sessions are not terminated
- File ownership remains unchanged
To fully prevent access, also expire the account: usermod --expiredate 1 username
Can usermod set passwords?
While usermod -p can set passwords, it requires pre-encrypted hashes and is not recommended. Use passwd instead:
# Good
passwd username
# Bad (requires encrypted hash)
usermod -p '$6$rounds=5000$saltsalt$hash...' username
How do I find all files owned by a user after UID change?
# Find files with the old UID
find /home /var /tmp -uid OLD_UID
# Find files without valid user (orphaned)
find /home /var /tmp -nouser
What’s the maximum UID I can use?
Standard Linux systems support:
- 32-bit systems: UID 0 to 65535
- 64-bit systems: UID 0 to 4294967295
However, many tools expect UIDs below 65536. Service accounts typically use UIDs below 1000, regular users 1000+.
Can I undo usermod changes?
Most changes can be reversed by applying the opposite:
# Rename back
usermod -l oldname newname
# Change UID back
usermod -u OLD_UID username
# Move home back
usermod -m -d /old/home username
# Remove from group
usermod -G "$(groups username | sed 's/.*: //; s/ groupname//')" username
Conclusion
The usermod command is a powerful and essential tool for Linux user account management. Its comprehensive set of options allows administrators to modify virtually every aspect of user accounts while maintaining system integrity through proper file locking and validation.
Key Takeaways
- Use
-awith-G: Always append (-a) when adding supplementary groups to avoid replacing existing memberships - Backup before major changes: UID changes and home directory moves should be preceded by backups
- Verify after changes: Confirm modifications with
id,groups, andgetent passwd - Mind logged-in users: UID changes and username changes require the user to be logged out
- Group changes require re-login: Supplementary group changes don’t take effect until the next login session
- Test in non-production: Complex modifications should be tested on test users first
When to Choose usermod
- ✅ Modifying any existing user account attribute
- ✅ Adding/removing users from groups
- ✅ Changing shells, home directories, or UIDs
- ✅ Locking/unlocking accounts
- ✅ Setting account expiration dates
- ❌ Creating new users (use
useradd) - ❌ Deleting users (use
userdel) - ❌ Detailed password aging (use
chage)
Mastering usermod is essential for effective Linux system administration. Combined with useradd, userdel, and chage, it provides complete control over user account lifecycle management.
Quick Reference Card
Common Operations
# Groups
usermod -aG group user # Add to supplementary group
usermod -G group1,group2 user # Set supplementary groups
usermod -g primarygroup user # Change primary group
# Account control
usermod -L user # Lock account
usermod -U user # Unlock account
usermod -e 2024-12-31 user # Set expiration
# User info
usermod -c "Full Name" user # Set GECOS
usermod -s /bin/bash user # Change shell
usermod -l newname oldname # Rename user
# Directories
usermod -d /new/home user # Change home path
usermod -m -d /new/home user # Move home directory
# UID
usermod -u 2000 user # Change UID
usermod -o -u 0 user # Allow duplicate UID (dangerous)
Verification Commands
id username # Show user info
groups username # Show group membership
getent passwd username # Show passwd entry
passwd -S username # Show password status
chage -l username # Show aging info
Safety Checklist
# Before major changes:
who | grep username # Check if logged in
groups username # Document current groups
tar czf backup.tar.gz /home/user # Backup home
# After changes:
id username # Verify changes
grep username /etc/passwd # Check passwd entry
find /home -uid OLD_UID # Find orphaned files
Ready to manage user accounts like a pro? Master usermod and handle any user modification task with confidence!
This tutorial covers the usermod command from the shadow-utils package. Options may vary slightly between Linux distributions. Always test in a non-production environment first.