Linux is a Unix-like and POSIX-compliant computer operating system assembled under the model of free and open source software development and distribution. The defining component of Linux is the Linux kernel, an operating system kernel first released on 5 October 1991 by Linus Torvalds.
Wednesday morning our monitoring solution suddenly alerted me to a critical issue with our main web server. Attempting to access our WordPress website via browser returned database connection errors, indicating a problem with our hosting environment. When I logged into the server via SSH, I discovered it’s a Linux Out of Memory (OOM) Killer terminating our MariaDB database service due to memory resource constraints. Below is my investigation into this incident revealed valuable insights about memory allocation, resource management, and strategies to prevent unwanted OOM Killer interventions in WordPress environments. Also, the server is very poorly spected on purpose so see how much we can push on resources. You will there’s other posts I’ve done recently that kind of goes around resource monitoring, restarting services etc.
If you’ve been following our series on server management and optimisation, you’ll know we’ve been experimenting with deliberately under-resourced servers to explore the limits of performance tuning. Our recent articles have covered:
- How to Automatically Restart Failed Services in Linux Using systemd
- How to Automatically Restart Failed Services in Linux Using Monit
- Atop vs Btop vs Htop vs Top: The Ultimate Linux Monitoring Tools Showdown
Today’s deep dive into OOM Killer management builds upon these previous explorations, showing how to maintain stability even when deliberately pushing resource boundaries.
Identifying OOM Killer Activity
After logging into our Linux server around 9:30 AM on 23 April 2025, my first troubleshooting step was examining system logs for clues about the database failure:
cd /var/log grep -i "error\|fail\|killed" syslog | tail -20
The telltale signature of the OOM Killer immediately appeared:
systemd[1]: mariadb.service: A process of this unit has been killed by the OOM killer. systemd[1]: mariadb.service: Main process exited, code=killed, status=9/KILL systemd[1]: mariadb.service: Failed with result 'oom-kill'.
These entries confirmed that MariaDB had been terminated by the OOM Killer mechanism, explaining our sudden database outage. But to implement proper solutions, I needed to understand what triggered the OOM Killer and how to prevent future incidents.
Investigating OOM Issues and Killer Behaviour
To comprehensively understand the events leading to OOM Killer activation, I extracted relevant syslog entries from around the incident time:
cat syslog | grep '2025-04-23T09' | egrep -v 'action-8-builtin'
This filtered log entries from 9 AM on 23 April, excluding noise from routine system tasks. The syslog revealed a clear sequence of memory allocation failures and resource constraints that triggered the OOM Killer.
Timeline of OOM Events and Killer Activation
9:23 AM: Early Warning Signs
The first warning signals appeared at 9:23 AM:
mariadbd[21566]: 2025-04-23 9:23:02 11749 [Warning] Aborted connection 11749 to db: 'wordpress_db' user: 'wordpress_user' host: 'localhost' (Got timeout reading communication packets)
Multiple database connection timeout errors occurred within a short timeframe. Then a critical memory management message appeared:
mariadbd[21566]: 2025-04-23 9:23:02 0 [Note] InnoDB: Memory pressure event freed 12409 pages
This indicated MariaDB’s InnoDB storage engine had detected memory pressure and was actively trying to reclaim memory by releasing its page cache—attempting to avoid triggering the OOM Killer.
System-wide memory issues soon followed:
systemd-journald[126]: Under memory pressure, flushing caches
This confirmed the entire system was experiencing significant memory pressure, forcing critical services to release cached memory to prevent OOM Killer activation.
9:24 AM: OOM Killer Activation and Process Termination
Just one minute later, the system reached a critical memory threshold triggering the OOM Killer:
kernel: php-fpm8.4 invoked oom-killer: gfp_mask=0x140cca(GFP_HIGHUSER_MOVABLE|__GFP_COMP), order=0, oom_score_adj=0
A PHP-FPM worker process attempted to allocate memory but failed due to insufficient resources, triggering the kernel’s OOM Killer mechanism. The kernel systematically examined all running processes to determine which to terminate.
After evaluating memory footprints, the OOM Killer selected its target:
kernel: Out of memory: Killed process 21566 (mariadbd) total-vm:2386824kB, anon-rss:380840kB, file-rss:8448kB, shmem-rss:0kB, UID:111 pgtables:1668kB oom_score_adj:0
The MariaDB database process was terminated because it consumed significant memory resources (approximately 380MB of physical RAM and 2.3GB of virtual memory). The OOM Killer determined this would free sufficient memory to maintain overall system stability and prevent a complete crash.
9:51 AM: Database Service Recovery
After investigating the OOM Killer event and implementing initial memory optimisations, I restarted the MariaDB service:
systemctl start mariadb.service
System logs confirmed successful recovery:
systemd[1]: Started mariadb.service - MariaDB 11.4.5 database server.
This restored database functionality to our WordPress site, but without addressing underlying memory issues, another OOM Killer intervention was inevitable.
Root Cause Analysis
The kernel memory information provided critical insights into our server’s memory allocation state:
Mem-Info: active_anon:280016 inactive_anon:141866 isolated_anon:0 active_file:157 inactive_file:5 isolated_file:0 unevictable:8954 dirty:0 writeback:0 slab_reclaimable:9184 slab_unreclaimable:20897 mapped:27465 shmem:51178 pagetables:9186 free:18913 free_pcp:1985 free_cma:0 Free swap = 0kB Total swap = 0kB
I immediately identified a critical configuration issue: Total swap = 0kB
. Our server had no swap space configured whatsoever. This removed an essential safety buffer for memory allocation spikes, making the system vulnerable to OOM conditions.
Additionally, over 50 PHP-FPM worker processes were running simultaneously, each consuming significant memory resources. This excessive number explained the severe memory pressure leading to the OOM condition.
The pattern of database connection timeouts provided another clue – our WordPress application appeared to have connection handling inefficiencies, potentially causing connection leaks that increased memory consumption across the system.
Implementing Solutions to Prevent OOM Killer Events
Based on my analysis, I implemented several targeted changes to optimise memory management:
1. Adding Swap Space
The first and most critical task was configuring swap space to provide an essential memory allocation buffer:
sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
I determined that 4GB was optimal for our WordPress server’s workload patterns. This swap configuration provides the kernel with additional virtual memory resources when physical RAM becomes constrained, helping prevent OOM conditions during traffic spikes.
2. Optimising PHP-FPM Memory Usage
Next, I discovered our PHP-FPM configuration used static process management with an excessive number of worker processes. I optimised the configuration in /etc/php/8.4/fpm/pool.d/www.conf
:
; Before - Configuration that led to OOM conditions pm = static pm.max_children = 50 ; After - Configuration to prevent OOM Killer activation pm = dynamic pm.max_children = 20 pm.start_servers = 5 pm.min_spare_servers = 3 pm.max_spare_servers = 10 pm.max_requests = 500
This change significantly reduced PHP memory consumption by decreasing maximum PHP-FPM workers from 50+ to a more efficient maximum of 20, while implementing dynamic scaling based on actual WordPress traffic. The pm.max_requests
setting ensures workers are periodically recycled to prevent memory leaks from accumulating.
3. Tuning MariaDB Memory Allocation
I performed a comprehensive review of our MariaDB configuration and implemented memory optimisations in /etc/mysql/mariadb.conf.d/50-server.cnf
:
[mysqld] # Reduced InnoDB buffer pool size to prevent OOM issues innodb_buffer_pool_size = 600M # Optimised per-connection memory buffers sort_buffer_size = 2M read_buffer_size = 2M join_buffer_size = 1M key_buffer_size = 20M # Disabled performance monitoring to reduce memory footprint performance_schema = OFF # Added connection limiting to prevent resource exhaustion max_connections = 100
These targeted optimisations reduced the database server’s overall memory footprint while maintaining adequate performance for WordPress operations. The buffer pool size adjustment was particularly important since this represents the largest memory allocation in a typical MariaDB installation.
4. Implementing Memory Monitoring
To proactively identify memory issues before they trigger the OOM Killer, I implemented a comprehensive monitoring solution with a specialised bash script:
#!/bin/bash # Memory monitoring script to detect potential OOM Killer conditions FREE_MEM=$(free -m | grep 'Mem:' | awk '{print $4}') FREE_SWAP=$(free -m | grep 'Swap:' | awk '{print $4}') TOTAL_AVAILABLE=$((FREE_MEM + FREE_SWAP)) if [ $FREE_MEM -lt 200 ]; then echo "WARNING: Critical memory pressure detected - OOM Killer risk" | echo "Free memory: $FREE_MEM MB" | echo "Free swap: $FREE_SWAP MB" | echo "Total available: $TOTAL_AVAILABLE MB" | echo "Top memory processes that could trigger the OOM Killer:" | ps aux --sort=-%mem | head -n 6 | /usr/bin/mail -s "OOM Risk Alert: Memory Low on $(hostname)" admin@example.com fi
I deployed this monitoring script to run regularly via crontab:
# Check memory every 5 minutes to catch potential OOM Killer conditions */5 * * * * /usr/local/bin/memory-check.sh
This solution provides early warning of potential OOM situations, allowing proactive action before the OOM Killer is triggered.
5. Configuring OOM Killer Priority
To make our mission-critical MariaDB service less likely to be terminated by the OOM Killer, I modified its OOM score adjustment value using systemd configuration:
# Create directory for MariaDB service customisations mkdir -p /etc/systemd/system/mariadb.service.d/ # Create OOM score adjustment configuration cat > /etc/systemd/system/mariadb.service.d/oom.conf << 'EOF' [Service] # Lower value (-1000 to 1000 scale) makes process less likely to be terminated OOMScoreAdjust=-900 EOF # Reload systemd to apply changes systemctl daemon-reload
This kernel configuration makes the MariaDB process much less likely to be selected by the OOM Killer algorithm. The OOMScoreAdjust value of -900 significantly reduces the likelihood of this critical service being terminated during OOM situations, directing the Killer to target less essential processes instead.
OOM Killer Management Key Lessons Learned
My investigation and resolution of this event taught me several crucial lessons about effective memory management:
- Configure Proper Swap Space: Even on servers with substantial RAM, swap space provides an essential buffer for memory allocation spikes and helps prevent OOM conditions. Never run production servers without properly configured swap.
- Monitor Database Connection Patterns: Database connection timeouts and aborted connections are early warning indicators of memory pressure and potential OOM conditions. These should trigger immediate investigation.
- Optimise PHP-FPM Worker Processes: Running excessive PHP-FPM worker processes is a leading cause of memory exhaustion in WordPress environments. Right-sizing these workers based on available system memory is critical for preventing OOM Killer events.
- Implement MariaDB Memory Tuning: Database servers require careful memory configuration tuning to balance performance requirements against overall system memory availability.
- Deploy Proactive Memory Monitoring: Waiting for OOM Killer events to occur is not a viable strategy. Implementing proactive monitoring with appropriate alerting thresholds helps detect potential issues before the kernel invokes the OOM Killer.
- Understand OOM Killer Selection Mechanisms: Developing a thorough understanding of how the OOM Killer selects processes for termination allows you to configure OOM score adjustments that protect your most critical services.
Results of Memory Optimisation Implementation
After implementing these memory management optimisations, our server’s resource utilisation patterns dramatically improved, and we have not experienced any additional OOM Killer events. The PHP-FPM worker configuration adjustments alone reduced our base memory consumption by approximately 30%, providing significantly more headroom for WordPress traffic spikes and background processes.
The addition of properly configured swap space has proven especially valuable during periodic high-traffic events, successfully preventing OOM Killer activation even during unexpected traffic surges. Our memory monitoring system has successfully identified several potential memory pressure incidents, allowing us to proactively investigate and resolve these issues before they triggered the OOM Killer mechanism.
The MariaDB memory optimisations have successfully balanced database performance with memory efficiency, maintaining good query response times while significantly reducing the database server’s memory footprint. WordPress page load times remain excellent despite the reduced memory allocation.
sudo systemctl status mariadb.service
● mariadb.service - MariaDB 11.4.5 database server
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; preset: enabled)
Drop-In: /etc/systemd/system/mariadb.service.d
└─limits.conf, migrated-from-my.cnf-settings.conf
Active: active (running) since Thu 2025-04-24 12:52:01 UTC; 5 days ago
Docs: man:mariadbd(8)
https://mariadb.com/kb/en/library/systemd/
Main PID: 9284 (mariadbd)
Status: "Taking your SQL requests now..."
Tasks: 24 (limit: 15050)
Memory: 770.4M (peak: 793.1M)
CPU: 1h 9min 48.291s
CGroup: /system.slice/mariadb.service
└─9284 /usr/sbin/mariadbd
Conclusion
This real-world investigation into OOM Killer events highlighted the critical importance of proper memory management for maintaining stable WordPress hosting environments. By thoroughly understanding how the OOM Killer works and implementing targeted optimisation measures, we’ve successfully created a more resilient and reliable server infrastructure that efficiently handles our WordPress workloads without memory-related service disruptions.
For anyone managing WordPress sites on Linux servers, I strongly recommend implementing these key memory optimisation strategies:
- Configuring appropriate swap space as a memory pressure buffer
- Optimising PHP-FPM worker process counts based on actual memory availability
- Fine-tuning MariaDB/MySQL memory parameters for your specific workload
- Implementing OOM score adjustments to protect mission-critical services
- Deploying proactive memory monitoring with appropriate alerting thresholds
- Regularly reviewing application code for memory leaks and inefficient resource usage
These memory management optimisations can help you prevent the unexpected service disruptions, potential data loss, and performance degradation that occur when the OOM Killer terminates essential processes. Proper memory configuration is not merely a performance consideration—it’s a fundamental requirement for maintaining reliable WordPress hosting operations.