Common Issues
Server Slow: RAM Full or OOM Killer
Diagnosis and fix when server is slow, process gets killed, or RAM is exhausted. Includes swap and optimizations.
Quick diagnosis
# Real-time memory usage
free -h
# Top processes by RAM consumption
ps aux --sort=-%mem | head -15
# Processes killed by OOM (Out of Memory)
dmesg | grep -i "killed process\|oom"
journalctl -k | grep -i "oom\|killed"Output of free -h:
total used free shared buff/cache available
Mem: 3.8Gi 3.6Gi 84Mi 12Mi 156Mi 154Mi
Swap: 0B 0B 0BIf available is less than 100-200 MB and swap is 0, system is in crisis.
OOM Killer: find the culprit
# Search in logs
journalctl -k --since "1 hour ago" | grep -i oom
# Example output:
# Out of memory: Kill process 1234 (mysql) score 850 or sacrifice child
# Killed process 1234 (mysql) total-vm:512MB, anon-rss:480MBIdentify what consumes RAM
# Top 10 processes by RSS (physical memory)
ps aux --sort=-%rss | awk 'NR<=11{printf "%-10s %-10s %s\n", $1, $3" "$4, $11}' | head -11
# Memory per systemd service
systemd-cgtop -n 1 --memory
# htop: press M to sort by memory
htopReal-time monitoring
# Update every 2 seconds
watch -n 2 'free -h && echo "---" && ps aux --sort=-%rss | head -8'Quick fixes
1. Free filesystem cache (safe, no data loss)
sync && echo 3 > /proc/sys/vm/drop_caches2. Restart services with memory leaks
# MySQL/MariaDB
systemctl restart mysql
# PHP-FPM
systemctl restart php8.1-fpm
# Nginx
systemctl reload nginx
# Redis
systemctl restart redis3. Add emergency swap
If you don't have swap configured:
# Create a 2 GB swap file
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# Make permanent
echo '/swapfile none swap sw 0 0' >> /etc/fstabSee the dedicated guide: Swap and swappiness.
Optimize MySQL for less RAM
MySQL is often the main consumer on small VPS.
nano /etc/mysql/mysql.conf.d/mysqld.cnf[mysqld]
# For VPS with 2 GB of RAM
innodb_buffer_pool_size = 256M # default: 128M, don't overdo it
innodb_buffer_pool_instances = 1
key_buffer_size = 32M
max_connections = 50 # reduce if you don't have many connections
thread_cache_size = 8
query_cache_type = 0 # disable query cache (obsolete)
tmp_table_size = 32M
max_heap_table_size = 32Msystemctl restart mysqlOptimal buffer pool calculation
# Empirical rule: 70-80% of available RAM for dedicated databases
# On 2 GB VPS with only MySQL: ~1.2 GB
# On 2 GB VPS with web server + MySQL: ~512 MBOptimize PHP-FPM
nano /etc/php/8.1/fpm/pool.d/www.conf; Reduces number of active PHP processes
pm = dynamic
pm.max_children = 10 # default 5 per GB of available RAM
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500 # restart processes after N requests (prevents leaks)systemctl restart php8.1-fpmOptimize Nginx
nano /etc/nginx/nginx.confworker_processes auto; # one worker per CPU core
worker_connections 1024; # reduce if you have little RAM
# Disable access log (saves I/O and some RAM)
access_log off;
# Memory caching for static files
open_file_cache max=1000 inactive=20s;Preventive monitoring
Alerting with bash script
nano /usr/local/bin/check-ram.sh#!/bin/bash
THRESHOLD=90 # percentage
TOTAL=$(free | awk '/Mem:/{print $2}')
USED=$(free | awk '/Mem:/{print $3}')
PERCENT=$((USED * 100 / TOTAL))
if [ $PERCENT -gt $THRESHOLD ]; then
echo "ALERT: RAM at ${PERCENT}% on $(hostname)" | \
mail -s "[ALERT] High RAM" admin@tuodominio.com
fichmod +x /usr/local/bin/check-ram.sh
# Run every 5 minutes
(crontab -l; echo "*/5 * * * * /usr/local/bin/check-ram.sh") | crontab -Netdata
For more complete monitoring with graphs and built-in alerting, see the guide Netdata.