Configure Linux user session limits with systemd and pam_limits for resource management

Intermediate 25 min Apr 16, 2026 151 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Learn to set up comprehensive user session resource limits using both traditional pam_limits.conf and modern systemd user slices. This tutorial covers memory, CPU, and process limits to prevent resource exhaustion on multi-user systems.

Prerequisites

  • Root or sudo access
  • Basic understanding of Linux user management
  • Familiarity with systemd and PAM concepts

What this solves

User session limits prevent individual users from consuming excessive system resources that could impact other users or crash the entire system. This becomes critical on shared servers, development environments, or production systems where multiple applications run under different user accounts. Without proper resource controls, a single runaway process or poorly configured application can monopolize CPU, memory, or file handles, causing system instability.

This tutorial combines traditional PAM limits with modern systemd user slice management to provide comprehensive resource control. You'll learn to set memory limits, CPU quotas, maximum processes, and file descriptor limits that automatically apply to user sessions and persist across reboots.

Understanding user session limits and resource control mechanisms

Linux provides two primary mechanisms for controlling user resource consumption: PAM limits (configured via /etc/security/limits.conf) and systemd user slices. PAM limits work at the session level and control traditional Unix resources like memory, file descriptors, and process counts. Systemd user slices provide more granular control over modern resources like CPU time and memory cgroups.

PAM limits apply when users log in through SSH, console, or display managers. They use the pam_limits module to enforce restrictions defined in the limits configuration files. These limits include both soft limits (warnings) and hard limits (absolute maximums) for various resources.

Systemd user slices automatically create a dedicated cgroup for each user session, allowing precise control over CPU usage, memory consumption, and I/O bandwidth. User slices persist as long as the user has active processes and can span multiple login sessions.

Note: Modern distributions increasingly rely on systemd for resource management, but PAM limits remain important for backward compatibility and certain resource types not handled by systemd.

Step-by-step configuration

Install required packages

Ensure you have the necessary PAM modules and systemd tools installed for resource management.

sudo apt update
sudo apt install -y libpam-modules systemd cgroup-tools
sudo dnf install -y pam systemd libcgroup-tools

Configure PAM limits for traditional resources

Set up basic resource limits using the PAM limits module. This configuration applies to all user sessions and controls fundamental Unix resources.

# Memory limits (in KB)
* soft as 2097152
* hard as 4194304

Maximum number of processes

* soft nproc 1024 * hard nproc 2048

Maximum number of open files

* soft nofile 4096 * hard nofile 8192

CPU time limits (in seconds)

* soft cpu 3600 * hard cpu 7200

Core dump size (in KB)

* soft core 0 * hard core 102400

Maximum file size (in KB)

* soft fsize 1048576 * hard fsize 2097152

Create user-specific limits

Configure specific limits for individual users or groups that require different resource allocations.

# Database user needs more memory and connections
mysql soft as 8388608
mysql hard as 16777216
mysql soft nproc 2048
mysql hard nproc 4096
mysql soft nofile 16384
mysql hard nofile 32768

Web server user limits

www-data soft as 4194304 www-data hard as 8388608 www-data soft nproc 512 www-data hard nproc 1024 www-data soft nofile 8192 www-data hard nofile 16384

Developer group gets higher limits

@developers soft nproc 4096 @developers hard nproc 8192 @developers soft nofile 8192 @developers hard nofile 16384

Configure systemd user slice limits

Create systemd user slice configuration to control modern cgroup resources like memory and CPU quotas.

[Unit]
Description=User Slice Resource Limits

[Slice]

Memory limit per user (2GB)

MemoryAccounting=yes MemoryLimit=2G

CPU quota (50% of one CPU core)

CPUAccounting=yes CPUQuota=50%

I/O limits

IOAccounting=yes IOReadBandwidthMax=/ 50M IOWriteBandwidthMax=/ 25M

Task limit (maximum processes/threads)

TasksAccounting=yes TasksMax=1024

Create the systemd configuration directory

Ensure the systemd user slice configuration directory exists and has correct permissions.

sudo mkdir -p /etc/systemd/system/user-.slice.d
sudo chown root:root /etc/systemd/system/user-.slice.d
sudo chmod 755 /etc/systemd/system/user-.slice.d

Configure specific user slice overrides

Create individual user slice configurations for users requiring different resource allocations.

sudo mkdir -p /etc/systemd/system/user-1001.slice.d
[Unit]
Description=Custom limits for user ID 1001

[Slice]

Higher memory limit for database user

MemoryAccounting=yes MemoryLimit=8G

More CPU resources

CPUAccounting=yes CPUQuota=200%

Higher task limit

TasksAccounting=yes TasksMax=4096

Enable PAM limits module

Ensure the PAM limits module is enabled in the system authentication configuration.

sudo grep -q "pam_limits.so" /etc/pam.d/common-session || echo "session required pam_limits.so" | sudo tee -a /etc/pam.d/common-session
Note: Most modern distributions enable pam_limits.so by default, but this command ensures it's present in the session configuration.

Reload systemd configuration

Apply the new systemd user slice configurations without requiring a system reboot.

sudo systemctl daemon-reload
sudo systemctl restart systemd-logind

Configure kernel parameters for resource management

Set kernel parameters that affect resource limits and memory management.

# Increase maximum number of memory map areas
vm.max_map_count = 262144

Adjust overcommit memory settings

vm.overcommit_memory = 1 vm.overcommit_ratio = 80

Increase maximum number of open files system-wide

fs.file-max = 1048576

Increase maximum number of processes

kernel.pid_max = 131072

Control swap usage

vm.swappiness = 10
sudo sysctl -p /etc/sysctl.d/99-user-limits.conf

Monitor and troubleshoot user resource consumption

Install monitoring tools

Install utilities for monitoring user resource consumption and troubleshooting limit issues.

sudo apt install -y htop iotop sysstat procps
sudo dnf install -y htop iotop sysstat procps-ng

Monitor user resource usage

Use various commands to monitor current user resource consumption and verify limits are working.

# Check current user limits
ulimit -a

View user processes and resource usage

ps auxf --sort=-%mem | head -20

Monitor user slice resource usage

sudo systemctl status user-$(id -u).slice

Check cgroup resource usage

sudo cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/memory.usage_in_bytes sudo cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/memory.limit_in_bytes

Create monitoring script

Develop a script to regularly monitor user resource consumption and alert on limit violations.

#!/bin/bash

Monitor user resource limits

LOG_FILE="/var/log/user-limits.log" DATE=$(date '+%Y-%m-%d %H:%M:%S') echo "[$DATE] User resource monitoring" >> "$LOG_FILE"

Check for users approaching limits

for USER_DIR in /sys/fs/cgroup/user.slice/user-*.slice; do if [ -d "$USER_DIR" ]; then USER_ID=$(basename "$USER_DIR" | sed 's/user-\([0-9]*\).slice/\1/') USER_NAME=$(getent passwd "$USER_ID" | cut -d: -f1) if [ -n "$USER_NAME" ]; then # Check memory usage MEMORY_USAGE=$(cat "$USER_DIR/memory.usage_in_bytes" 2>/dev/null || echo 0) MEMORY_LIMIT=$(cat "$USER_DIR/memory.limit_in_bytes" 2>/dev/null || echo 0) if [ "$MEMORY_LIMIT" -gt 0 ] && [ "$MEMORY_USAGE" -gt 0 ]; then MEMORY_PERCENT=$((MEMORY_USAGE * 100 / MEMORY_LIMIT)) if [ "$MEMORY_PERCENT" -gt 80 ]; then echo "[$DATE] WARNING: User $USER_NAME using ${MEMORY_PERCENT}% of memory limit" >> "$LOG_FILE" fi fi # Check task count TASK_CURRENT=$(cat "$USER_DIR/pids.current" 2>/dev/null || echo 0) TASK_LIMIT=$(cat "$USER_DIR/pids.max" 2>/dev/null || echo 0) if [ "$TASK_LIMIT" != "max" ] && [ "$TASK_CURRENT" -gt 0 ] && [ "$TASK_LIMIT" -gt 0 ]; then TASK_PERCENT=$((TASK_CURRENT * 100 / TASK_LIMIT)) if [ "$TASK_PERCENT" -gt 80 ]; then echo "[$DATE] WARNING: User $USER_NAME using ${TASK_PERCENT}% of task limit" >> "$LOG_FILE" fi fi fi fi done
sudo chmod 755 /usr/local/bin/monitor-user-limits.sh

Set up automated monitoring

Create a systemd timer to run the monitoring script periodically.

[Unit]
Description=Monitor User Resource Limits
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/monitor-user-limits.sh
User=root
Group=root
[Unit]
Description=Run user limits monitoring every 5 minutes
Requires=monitor-user-limits.service

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now monitor-user-limits.timer

Verify your setup

Test that your user session limits are properly configured and functioning as expected.

# Check current user limits
ulimit -a

Test soft limits (should work)

ulimit -n 4096 echo "Soft limit test: $?"

Test hard limits (should fail if exceeded)

ulimit -n 16384 echo "Hard limit test: $?"

View systemd user slice status

sudo systemctl status user-$(id -u).slice

Check cgroup limits

find /sys/fs/cgroup -name "user-$(id -u).slice" -type d 2>/dev/null

Verify PAM limits module is loaded

sudo grep pam_limits /etc/pam.d/common-session

Check monitoring timer

sudo systemctl status monitor-user-limits.timer

Create a test to verify memory limits are enforced by attempting to allocate memory beyond the configured limit. Use the stress tool to simulate resource consumption and observe how limits prevent system overload. The monitoring tools you configured will help track resource usage and identify when users approach their allocated limits.

Common issues

SymptomCauseFix
Limits not applied to SSH sessionsPAM limits module not enabledAdd session required pam_limits.so to /etc/pam.d/sshd
Systemd limits not workingUser slice configuration not loadedsudo systemctl daemon-reload && sudo systemctl restart systemd-logind
Memory limits not enforcedCgroup v1 vs v2 compatibilityCheck /sys/fs/cgroup structure and use appropriate syntax
Process limits too restrictiveHard limits set too lowIncrease limits in /etc/security/limits.conf and reload PAM
Application fails to startFile descriptor limits too lowIncrease nofile limits for specific user or service
Monitoring script not runningTimer not enabled or permissions issueCheck timer status and log file permissions

Advanced configuration options

Fine-tune your resource management setup with additional configuration options for specific use cases. You can integrate user limits with system performance monitoring tools to create comprehensive resource tracking. For database servers, consider specialized limits that account for connection pooling and query processing requirements.

Enterprise environments may benefit from integrating user limits with centralized logging systems to track resource usage patterns across multiple servers. This helps identify users who consistently approach their limits and may need adjusted quotas or optimization guidance.

Consider implementing graduated limits where users start with conservative resource allocations and can request increases based on demonstrated need. This approach prevents resource waste while accommodating legitimate high-resource applications.

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.