When dealing with memory-intensive applications like MySQL configured to use large pages, we often hit a wall with traditional limits.conf
approaches. The fundamental issue lies in how PAM (Pluggable Authentication Modules) initializes - system services started during boot don't inherit these limits because they're not spawned through login shells.
The /etc/security/limits.conf
file requires pam_limits.so
to be loaded during session initialization. For systemd services (or traditional SysV init scripts), this simply doesn't happen during the early boot phase. This explains why your MySQL service might ignore the memlock
limits needed for large pages.
For modern systems using systemd, we have cleaner approaches than modifying init scripts:
# Method 1: Directly in the service unit file
[Service]
LimitMEMLOCK=infinity
# Method 2: Using drop-in files (recommended)
# Create /etc/systemd/system/mysql.service.d/limits.conf
[Service]
LimitMEMLOCK=infinity
After creating/modifying these files, run:
systemctl daemon-reload
systemctl restart mysql
For systems still using SysV init scripts, you have several options:
# Option 1: Modify the init script directly (not recommended)
# Add this near the start of the start() function:
ulimit -l unlimited
# Option 2: Create a wrapper script
#!/bin/bash
ulimit -l unlimited
exec /usr/sbin/mysqld "$@"
Since you're managing servers with Chef, here's how to implement this properly without overriding RPM-managed files:
# For systemd systems
directory '/etc/systemd/system/mysql.service.d' do
owner 'root'
group 'root'
mode '0755'
action :create
end
file '/etc/systemd/system/mysql.service.d/limits.conf' do
content "[Service]\nLimitMEMLOCK=infinity\n"
owner 'root'
group 'root'
mode '0644'
notifies :run, 'execute[systemctl-daemon-reload]', :immediately
end
execute 'systemctl-daemon-reload' do
command 'systemctl daemon-reload'
action :nothing
end
After implementation, verify your settings:
# Check effective limits
cat /proc/$(pgrep mysqld)/limits | grep locked
# Alternative method for systemd
systemctl show mysql | grep LimitMEMLOCK
If you encounter issues, check:
- Systemd version (needs to be >= 219 for some limit features)
- AppArmor/SELinux constraints
- Whether your system actually supports large pages
When enabling MySQL large pages support, we often need to set ulimit -l
for locked memory. While /etc/security/limits.conf
works for shell sessions, it doesn't affect system services during boot because:
- PAM (pluggable authentication modules) only processes limits for login sessions
- Systemd services ignore traditional Unix limits configuration
- RPM-managed init scripts shouldn't be directly modified
The most maintainable solution is creating a systemd drop-in file without modifying the original service unit:
# Create directory if not exists
sudo mkdir -p /etc/systemd/system/mysql.service.d/
# Create override file
sudo tee /etc/systemd/system/mysql.service.d/override.conf << 'EOF'
[Service]
LimitMEMLOCK=infinity
EOF
# Reload systemd and restart MySQL
sudo systemctl daemon-reload
sudo systemctl restart mysql
After implementation, verify the settings with these commands:
# Check applied limits
systemctl show mysql | grep LimitMEMLOCK
# Verify from MySQL process
cat /proc/$(pgrep mysqld)/limits | grep locked
For infrastructure-as-code environments like Chef, implement this as:
directory '/etc/systemd/system/mysql.service.d' do
owner 'root'
group 'root'
mode '0755'
action :create
end
file '/etc/systemd/system/mysql.service.d/override.conf' do
content <<-EOF
[Service]
LimitMEMLOCK=infinity
EOF
notifies :run, 'execute[systemctl-daemon-reload]', :immediately
end
execute 'systemctl-daemon-reload' do
command 'systemctl daemon-reload'
action :nothing
end
service 'mysql' do
action [:restart]
end
For non-systemd systems or special cases:
# Option 1: SysV init wrapper
cat > /etc/init.d/mysql-wrapper << 'EOF'
#!/bin/sh
ulimit -l unlimited
/etc/init.d/mysql-original "$@"
EOF
# Option 2: Profile.d script
echo "ulimit -l unlimited" > /etc/profile.d/mysql_limits.sh