useradd command creates new user accounts on Linux systems. It's the low-level utility for adding users and requires manual configuration of passwords and other settings. For interactive user creation, see adduser (a higher-level wrapper).
useradd requires root privileges. Always use sudo or run as root. Remember to set a password with passwd after creating the user.
Create a minimal user account:
sudo useradd john
What happens:
After creating, you should:
# Set password to enable login sudo passwd john # Verify user was created id john grep john /etc/passwd
Expected output:
uid=1001(john) gid=1001(john) groups=1001(john)
passwd after useradd.
Create user with a home directory automatically:
sudo useradd -m john
What it does:
-m creates home directory at /home/johnVerify home directory:
ls -la /home/john
Complete user creation with all basics:
# Create user with home directory and set shell sudo useradd -m -s /bin/bash john # Set password sudo passwd john # User can now login!
-m when creating regular users. Without it, users may not have necessary startup files and directories.
Specify which shell the user will use:
sudo useradd -m -s /bin/bash john
Common shells:
# Bash (most common) sudo useradd -m -s /bin/bash john # Zsh (modern, feature-rich) sudo useradd -m -s /bin/zsh jane # Restricted shell (limited commands) sudo useradd -m -s /bin/rbash restricted_user # No shell (for service accounts) sudo useradd -s /sbin/nologin serviceaccount # No shell, cannot login at all sudo useradd -s /bin/false lockedaccount
Verify shell assignment:
grep john /etc/passwd john:x:1001:1001::/home/john:/bin/bash
When to use different shells:
/bin/bash - Regular users (default, recommended)/bin/zsh - Power users who prefer Zsh/sbin/nologin - Service accounts (daemons, system processes)/bin/false - Completely disabled accountsAssign specific user ID and group ID:
sudo useradd -m -u 1500 -g 1500 john
Options explained:
-u 1500 - Set user ID to 1500-g 1500 - Set primary group ID to 1500Why use specific UIDs?
Create user with group that doesn't exist yet:
# First create the group sudo groupadd -g 1500 developers # Then create user with that group sudo useradd -m -u 1500 -g developers john # Verify id john uid=1500(john) gid=1500(developers) groups=1500(developers)
Add user to supplementary groups during creation:
sudo useradd -m -G wheel,docker,developers john
Options:
-G wheel,docker,developers - Supplementary groups (comma-separated, no spaces)-g specifies otherwiseCommon group assignments:
# Admin user with sudo access sudo useradd -m -G wheel,sudo john # Developer account sudo useradd -m -G developers,docker,git jane # Web server account sudo useradd -m -G www-data,developers webdev # Database administrator sudo useradd -m -G dba,developers,sudo dbadmin
Verify group memberships:
groups john id john
Important groups:
wheel or sudo - Administrative privilegesdocker - Docker access without sudowww-data - Web server file accessdevelopers - Shared development resourcesSpecify non-default home directory location:
sudo useradd -m -d /opt/users/john john
Options:
-d /opt/users/john - Custom home directory path-m - Create the directory if it doesn't existUse cases for custom home directories:
# Store homes on separate partition sudo useradd -m -d /data/home/john john # Shared project directory as home sudo useradd -m -d /projects/webapp/users/developer developer # Service account with custom path sudo useradd -d /var/lib/myapp -s /sbin/nologin myapp # Multiple user hierarchies sudo useradd -m -d /contractors/john john
Create without automatic directory creation:
# Specify directory but don't create it sudo useradd -d /custom/path/john -M john # Later create manually with proper permissions sudo mkdir -p /custom/path/john sudo chown john:john /custom/path/john sudo chmod 755 /custom/path/john
Create account for running services/daemons:
sudo useradd -r -s /sbin/nologin nginx
Options for system accounts:
-r - Create system account (UID < 1000)-s /sbin/nologin - No login shellCommon service account patterns:
# Web server user sudo useradd -r -s /sbin/nologin -d /var/www nginx # Database user sudo useradd -r -s /sbin/nologin -d /var/lib/mysql mysql # Application user with home directory sudo useradd -r -m -s /sbin/nologin -d /opt/myapp myapp # Container user sudo useradd -r -s /bin/false -M containeruser
Why use system accounts?
/sbin/nologin or /bin/false.
Set automatic account expiration date:
sudo useradd -m -e 2026-12-31 contractor
Options:
-e YYYY-MM-DD - Account expires on specified datePractical examples:
# Contractor account (3 months) sudo useradd -m -e $(date -d '+3 months' +%Y-%m-%d) contractor_john # Intern account (summer only) sudo useradd -m -e 2026-08-31 intern_jane # Temporary test account (1 week) sudo useradd -m -e $(date -d '+1 week' +%Y-%m-%d) testuser # Student account (semester end) sudo useradd -m -e 2026-05-15 student_bob
Check expiration status:
sudo chage -l contractor # Shows: Account expires : Dec 31, 2026
Remove expiration date:
sudo chage -E -1 contractor
Extend expiration:
sudo chage -E 2027-12-31 contractor
Automate creation of multiple users from a file:
#!/bin/bash
# bulk-create-users.sh - Create multiple users from CSV
# CSV format: username,fullname,groups,expire_date
# Example: jdoe,John Doe,developers,2026-12-31
USER_FILE="${1:-users.csv}"
if [ ! -f "$USER_FILE" ]; then
echo "Error: File $USER_FILE not found"
echo "Usage: $0 <users_csv_file>"
exit 1
fi
echo "Creating users from $USER_FILE..."
echo ""
while IFS=',' read -r username fullname groups expire_date; do
# Skip header line
if [ "$username" = "username" ]; then
continue
fi
echo "Creating user: $username ($fullname)"
# Build useradd command
CMD="sudo useradd -m -c \"$fullname\" -s /bin/bash"
# Add groups if specified
if [ -n "$groups" ]; then
CMD="$CMD -G $groups"
fi
# Add expiration if specified
if [ -n "$expire_date" ]; then
CMD="$CMD -e $expire_date"
fi
# Add username
CMD="$CMD $username"
# Execute command
eval $CMD
# Set random initial password
RANDOM_PASS=$(openssl rand -base64 12)
echo "$username:$RANDOM_PASS" | sudo chpasswd
# Force password change on first login
sudo chage -d 0 $username
# Save credentials to file
echo "$username,$RANDOM_PASS" >> /tmp/user_credentials.txt
echo " ✓ User $username created"
echo " - Initial password saved to /tmp/user_credentials.txt"
echo " - User must change password on first login"
echo ""
done < "$USER_FILE"
echo "User creation complete!"
echo "Credentials saved to: /tmp/user_credentials.txt"
echo "Remember to distribute passwords securely and delete the file!"
Sample CSV file (users.csv):
username,fullname,groups,expire_date jdoe,John Doe,developers,2027-12-31 jsmith,Jane Smith,"developers,sudo", contractor1,Bob Wilson,contractors,2026-06-30 intern_alice,Alice Brown,interns,2026-08-31
Usage:
bash bulk-create-users.sh users.csv
Create a fully configured user with all recommended settings:
#!/bin/bash
# create-complete-user.sh - Create user with all best practices
USERNAME=$1
FULLNAME=$2
if [ -z "$USERNAME" ] || [ -z "$FULLNAME" ]; then
echo "Usage: $0 <username> <full name>"
echo "Example: $0 jdoe 'John Doe'"
exit 1
fi
echo "Creating complete user account for: $FULLNAME ($USERNAME)"
echo ""
# 1. Create user with home directory and bash shell
echo "1. Creating user account..."
sudo useradd -m -s /bin/bash -c "$FULLNAME" $USERNAME
# 2. Add to appropriate groups
echo "2. Adding to standard groups..."
sudo usermod -aG sudo,developers $USERNAME
# 3. Set up proper home directory permissions
echo "3. Setting home directory permissions..."
sudo chmod 750 /home/$USERNAME
# 4. Generate and set initial password
echo "4. Setting initial password..."
RANDOM_PASS=$(openssl rand -base64 16)
echo "$USERNAME:$RANDOM_PASS" | sudo chpasswd
# 5. Force password change on first login
echo "5. Forcing password change on first login..."
sudo chage -d 0 $USERNAME
# 6. Set password aging policy
echo "6. Setting password aging policy..."
sudo chage -M 90 -m 7 -W 14 -I 30 $USERNAME
# 7. Create common directories
echo "7. Creating user directories..."
sudo mkdir -p /home/$USERNAME/{Documents,Downloads,Projects}
sudo chown -R $USERNAME:$USERNAME /home/$USERNAME
# 8. Copy custom config files if they exist
echo "8. Setting up user environment..."
if [ -d /etc/skel.custom ]; then
sudo cp -r /etc/skel.custom/. /home/$USERNAME/
sudo chown -R $USERNAME:$USERNAME /home/$USERNAME
fi
# 9. Set up SSH directory
echo "9. Creating SSH directory..."
sudo mkdir -p /home/$USERNAME/.ssh
sudo chmod 700 /home/$USERNAME/.ssh
sudo touch /home/$USERNAME/.ssh/authorized_keys
sudo chmod 600 /home/$USERNAME/.ssh/authorized_keys
sudo chown -R $USERNAME:$USERNAME /home/$USERNAME/.ssh
# 10. Log the creation
echo "10. Logging user creation..."
echo "$(date): Created user $USERNAME ($FULLNAME)" | \
sudo tee -a /var/log/user_creation.log
# Summary
echo ""
echo "=========================================="
echo "User Creation Complete!"
echo "=========================================="
echo "Username: $USERNAME"
echo "Full Name: $FULLNAME"
echo "Home Directory: /home/$USERNAME"
echo "Groups: $(groups $USERNAME)"
echo "Initial Password: $RANDOM_PASS"
echo ""
echo "IMPORTANT:"
echo "- User must change password on first login"
echo "- Password expires in 90 days"
echo "- SSH directory ready for key upload"
echo "- Credentials logged to /var/log/user_creation.log"
echo ""
echo "To set up SSH key:"
echo " sudo -u $USERNAME ssh-keygen"
echo ""
echo "To view password aging info:"
echo " sudo chage -l $USERNAME"
echo "=========================================="
Usage:
sudo bash create-complete-user.sh jdoe "John Doe"
| Option | Description | Example |
|---|---|---|
-m |
Create home directory | useradd -m john |
-M |
Do not create home directory | useradd -M serviceaccount |
-d DIR |
Specify home directory path | useradd -m -d /custom/home john |
-s SHELL |
Specify login shell | useradd -s /bin/bash john |
-u UID |
Specify user ID | useradd -u 1500 john |
-g GID |
Specify primary group ID | useradd -g 1500 john |
-G GROUPS |
Specify supplementary groups | useradd -G wheel,docker john |
-c COMMENT |
Add comment (full name) | useradd -c "John Doe" john |
-e DATE |
Set account expiration date | useradd -e 2026-12-31 john |
-r |
Create system account | useradd -r nginx |
-k SKEL |
Specify skeleton directory | useradd -m -k /etc/skel.custom john |
-p PASSWORD |
Set encrypted password | useradd -p $(openssl passwd -1 pass) john |
| Feature | useradd (low-level) | adduser (high-level) |
|---|---|---|
| Interface | Command-line only | Interactive prompts |
| Home Directory | Must specify -m | Created automatically |
| Password | Must set separately with passwd | Prompts during creation |
| Availability | All Linux distributions | Debian/Ubuntu mainly |
| Use Case | Scripts, automation | Manual, interactive use |
User account information:
john:x:1001:1001:John Doe:/home/john:/bin/bash
Fields: username:password:UID:GID:comment:home:shell
Encrypted passwords and aging information:
john:$6$encrypted...:18993:0:99999:7:::
Group information:
developers:x:1001:john,jane,bob
Default values for useradd:
GROUP=100 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/bash SKEL=/etc/skel
Skeleton directory copied to new user homes:
.bashrc .bash_profile .profile
passwd after useraddchage -d 0 for new accounts-c to add full name/purpose-r and /sbin/nologin-e for contractors, interns| Task | Command |
|---|---|
| Basic user | sudo useradd -m -s /bin/bash john |
| User with groups | sudo useradd -m -G sudo,developers john |
| System account | sudo useradd -r -s /sbin/nologin service |
| With expiration | sudo useradd -m -e 2026-12-31 contractor |
| Custom UID | sudo useradd -m -u 1500 john |
| Set password | sudo passwd john |