How to Apply /etc/security/limits.conf Changes Without Reboot for SSH Sessions


6 views

When modifying system resource limits through /etc/security/limits.conf, many administrators encounter a persistent issue: changes don't take effect for existing SSH sessions without a full system reboot. This becomes particularly problematic when implementing memory restrictions like:

*        soft    rss             64000000
*        hard    nofile          50000
*        soft    nofile          1024

While su - user properly reloads limits, SSH sessions mysteriously resist changes. This occurs because PAM (Pluggable Authentication Modules) only applies these limits during the initial authentication phase. The SSH daemon maintains existing sessions without reapplying the updated limits.

Here are proven methods to enforce new limits for SSH users:

# Method 1: Restart SSHD service (preserves existing connections)
sudo systemctl restart sshd

# Method 2: Kill all existing SSH sessions
sudo pkill -9 sshd && sudo systemctl start sshd

After applying changes, test with:

# For memory limits verification
ulimit -S -v
ulimit -H -v

# For file descriptor verification
ulimit -S -n
ulimit -H -n

For more granular control, create files in /etc/security/limits.d/:

# /etc/security/limits.d/90-developers.conf
@developers hard nofile 65000
@developers soft rss 128000000

Ensure your PAM stack includes these critical elements:

# /etc/pam.d/sshd should contain:
session required pam_limits.so
session required pam_env.so

# Verify SSHD config contains:
UsePAM yes

When modifying /etc/security/limits.conf to implement memory and file descriptor controls, the changes don't automatically apply to existing sessions. The behavior differs between local logins (su - user) and SSH connections, even with proper PAM configuration.

# Typical working PAM stack for su:
auth       required   pam_env.so
auth       required   pam_limits.so  # Critical for session-init

# Common SSH PAM caveat:
session    required   pam_limits.so  # Often appears too late in the stack

SSH sessions initialize limits differently because of two factors:

  • The PAM module ordering in /etc/pam.d/sshd
  • SSH's own internal limit handling that may override PAM

1. Force PAM Reinitialization

For existing SSH sessions, execute:

# As root:
pam_exec -v -d5 /etc/security/limits.conf

# Alternative method:
service sshd reload && pkill -PAM sshd

2. Verify PAM Configuration

Ensure your /etc/pam.d/sshd contains:

# Place this early in the file
session    required     pam_limits.so
session    optional     pam_exec.so /etc/security/limits.d/refresh.sh

3. Immediate Testing Methodology

To verify without reboot:

# Test sequence:
ssh user@localhost -t "ulimit -a; grep 'Max open files' /proc/self/limits"

# Expected output matching your limits.conf:
Max open files            1024                50000

For granular control, create /etc/security/limits.d/90-custom.conf:

# Memory limits
*               soft    rss         64000000
@powerusers     hard    rss         unlimited

# File descriptors
*               soft    nofile      1024
*               hard    nofile      50000
@devteam        hard    nofile      100000
  1. grep pam_limits /etc/pam.d/* for module presence
  2. ssh -vvv user@localhost to trace PAM initialization
  3. cat /proc/$(pgrep sshd)/limits for daemon-level limits

For systemd systems, create /etc/systemd/system/ssh-refresh.service:

[Unit]
Description=SSH limits refresh
After=network.target

[Service]
ExecStart=/bin/bash -c "sysctl -p /etc/sysctl.d/*.conf && /sbin/pam_limits"

[Install]
WantedBy=multi-user.target