Cómo Optimizar MySQL my.cnf en VPS Pequeña (1-2 GB RAM) sin Caídas
Aprende a optimizar MySQL my.cnf en VPS pequeña: ajustar InnoDB buffer pool, desactivar performance_schema y reducir RAM sin perder throughput.
Una VPS de 1 o 2 GB de RAM es el punto donde MySQL con valores por defecto
empieza a doler. El proceso mysqld ocupa ~450 MB en el arranque, tu
aplicación PHP/Node queda apretada, el kernel empieza a matar procesos por
OOM y el swap entra en acción destruyendo el I/O. El problema raramente es
MySQL en sí — es el my.cnf por defecto, calibrado para un servidor
genérico de 8 GB.
Este tutorial cubre los ajustes de my.cnf que realmente importan en una
VPS pequeña: dimensionar innodb_buffer_pool_size para la realidad de la
máquina, desactivar performance_schema cuando tiene sentido, controlar
conexiones y log binario, y validar todo con comandos que ejecutas antes y
después. La persona destinataria es un developer que levantó MySQL 8 o
MariaDB en un droplet de 1-2 GB, vio al mysqld consumir 40% de la RAM y
quiere reducir sin perder rendimiento.
Tiempo de ejecución: 20-30 minutos incluyendo respaldo del my.cnf
original, edición, reinicio y medición. Los ajustes valen para MySQL 8.0+
y MariaDB 10.6+ en Ubuntu 22.04/24.04 LTS y Debian 12.
Requisitos previos
VPS Linux (Ubuntu 22.04/24.04 LTS o Debian 12) con 1 o 2 GB de RAM,
MySQL 8.0+ o MariaDB 10.6+ instalado y en ejecución, acceso sudo y
credenciales del root de MySQL. Haz un respaldo de la base antes —
mysqldump --single-transaction --all-databases > backup.sql — porque un
reinicio con un my.cnf roto puede impedir que el servicio levante.
Confirma lo que tienes hoy antes de tocar cualquier línea:
free -m ps -o rss= -p $(pidof mysqld) mysql --version /etc/mysql/mysql.conf.d/mysqld.cnf En MariaDB, el archivo principal es /etc/mysql/mariadb.conf.d/50-server.cnf.
En ambos, la regla es la misma: no edites /etc/mysql/my.cnf directamente
— solo hace !includedir de los archivos en las carpetas mysql.conf.d/
o mariadb.conf.d/.
Diagnóstico del consumo actual
Antes de recortar, mide. Sin línea base, no sabes si el ajuste mejoró.
Mira el RSS actual de mysqld y cuánto representa de la RAM:
ps -o pid,rss,cmd -p $(pidof mysqld)
free -mEl valor de rss está en KB. Divide por 1024 para tener MB. En VPS de 1 GB
con MySQL 8 por defecto, espera ver entre 380 y 500 MB — muy por encima de
lo necesario para la carga real de un sitio pequeño.
Mira el uso real del InnoDB buffer pool — si el pool por defecto de 128 MB sobra o falta:
mysql -u root -p -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages%';"Qué interpretar:
pages_total= tamaño del pool en páginas de 16 KBpages_freecerca de cero = pool lleno, MySQL está reciclando páginaspages_data/pages_total= cuánto está en uso útil
Si pages_free está alto (>30% del total) y el servidor lleva días de
uptime, puedes reducir el pool sin perjuicio. Si está cerca de cero e
Innodb_buffer_pool_reads (no read_requests) crece rápido, el pool está
infradimensionado.
Revisa performance_schema — solo él consume 70-100 MB:
mysql -u root -p -e "SELECT SUM(MEMORY_USED)/1024/1024 AS mb FROM sys.x\$memory_global_by_current_bytes;"En VPS de 1 GB sin una herramienta de profiling externa leyéndolo, es el primer candidato a desactivar.
Editando el my.cnf
Crea un archivo propio de override en lugar de tocar el mysqld.cnf por
defecto — así, las actualizaciones del paquete no sobrescriben tus
ajustes.
Crea el archivo de override:
sudo nano /etc/mysql/mysql.conf.d/99-hostini-tuning.cnfEn MariaDB: /etc/mysql/mariadb.conf.d/99-hostini-tuning.cnf. El número
99 garantiza que este archivo se lee al final — sobrescribe cualquier
valor por defecto.
Pega esta configuración base para VPS de 1 GB de RAM:
[mysqld]
# InnoDB — corazón de MySQL
innodb_buffer_pool_size = 256M
innodb_buffer_pool_instances = 1
innodb_log_buffer_size = 8M
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 2
# Conexiones — una VPS pequeña no aguanta 150
max_connections = 50
thread_cache_size = 8
table_open_cache = 200
table_definition_cache = 400
# Performance schema — desactivado en 1 GB
performance_schema = OFF
# Binary log — desactivado si NO usas replicación
disable_log_bin
# Para MariaDB usa: skip-log-bin
# Logs lentos para diagnóstico
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# Temporales — en RAM hasta este límite
tmp_table_size = 16M
max_heap_table_size = 16M
# Sort/join buffers — por conexión, cuidado con max_connections
sort_buffer_size = 256K
join_buffer_size = 256K
read_buffer_size = 128K
read_rnd_buffer_size = 256KPara VPS de 2 GB, ajusta solo estas líneas:
innodb_buffer_pool_size = 512M
max_connections = 100
performance_schema = ON
performance-schema-instrument='memory/%=COUNTED'sort_buffer_size y join_buffer_size se asignan POR CONEXIÓN ACTIVA, no
globalmente. Subir cada uno a 4 MB con 100 conexiones = 400 MB potenciales
solo en esos buffers. Los valores bajos del snippet (256K) son
intencionales — una query lenta en VPS pequeña se resuelve con un índice,
no con un buffer mayor.
Guarda (Ctrl+O, Enter, Ctrl+X) y valida la sintaxis antes del
reinicio:
sudo mysqld --validate-configSi aparece cualquier error, el servicio no levantará después del reinicio. Corrige antes de continuar. Salida esperada: ninguna línea (el silencio es éxito).
Reinicia MySQL y revisa el estado:
sudo systemctl restart mysql
sudo systemctl status mysql --no-pagerEn MariaDB: sudo systemctl restart mariadb. Si el estado muestra
active (running), sigues adelante. Si falló, lee el motivo en
sudo journalctl -u mysql -n 50 — casi siempre es un typo en el .cnf.
Verificación
Confirma que los ajustes aplicaron y que apareció el ahorro de RAM.
Confirma los valores que entraron en vigor:
mysql -u root -p -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_buffer_pool_size', 'max_connections', 'performance_schema', 'log_bin', 'tmp_table_size');"Los valores deben coincidir con lo que pusiste en 99-hostini-tuning.cnf.
Si alguno muestra el default antiguo, el archivo no se está leyendo —
verifica la ruta y los permisos (debe ser 644 root:root).
Mide el consumo de RAM nuevamente:
ps -o pid,rss,cmd -p $(pidof mysqld)
free -mExpectativa post-ajuste en VPS de 1 GB: mysqld en ~280-340 MB (caída de
~30%). En 2 GB con performance_schema activado: ~500-580 MB. Espera unos
minutos con tráfico real antes de la medición final — el pool se calienta
y se estabiliza.
Ejecuta SHOW STATUS después de 1-2 horas de uso real y confirma que el buffer pool no está ahogándose:
mysql -u root -p -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_%';"Señales de salud: pages_free > 5% del pages_total, reads creciendo
despacio comparado con read_requests (ratio de hit > 99%). Si reads
explota, sube el buffer pool en 64 MB y vuelve a probar.
Resolución de problemas
MySQL no levanta tras el reinicio
Revisa el log del journal e identifica la línea exacta que rompió:
sudo journalctl -u mysql -n 80 --no-pager
Causas comunes: innodb_buffer_pool_size mayor que la RAM total
disponible, O_DIRECT en un filesystem que no lo soporta (raro en
ext4/xfs), opción deprecada en MySQL 8 (query_cache_size fue eliminado).
Revierte tu 99-hostini-tuning.cnf a la base mínima (solo
innodb_buffer_pool_size) y agrega línea por línea.
”Out of memory” en la aplicación tras el ajuste
Redujiste la RAM de MySQL pero la app creció para llenarla. Ejecuta
free -m durante carga real y mira si available cae por debajo de
100 MB. Si es así, considera un swappiness más bajo
(sudo sysctl vm.swappiness=10) y activa un archivo de swap de 1 GB como
red de protección — no es solución de producción, pero evita el OOM kill
mientras dimensionas mejor.
Queries que antes eran rápidas se volvieron lentas
Síntoma típico de buffer pool demasiado pequeño — antes la tabla cabía en
RAM, ahora no. Revisa Innodb_buffer_pool_reads (no read_requests) en
SHOW GLOBAL STATUS antes y después. Si subió drásticamente, aumenta
innodb_buffer_pool_size en 64 MB y mide de nuevo. Solución estructural:
agregar un índice en la query, no inflar el pool.
Próximos pasos
Con el my.cnf ajustado, vale la pena consolidar la operación:
- Configura rotación de logs lentos (
slow.logcrece rápido) víalogrotateen/etc/logrotate.d/mysql-server - Agenda
mysqldump --single-transactiondiario concrony envíalo a almacenamiento externo (rclone + S3 o Backblaze B2) - En producción con replicación o point-in-time recovery, mantén
log_binactivado y ajustaexpire_logs_days = 7para controlar el disco - Considera subir a una VPS con más RAM si el pool de 256 MB no da abasto — en general, el salto a 4 GB elimina el ajuste fino y te libera para enfocarte en el producto
Una VPS Hostini ya viene con SSD NVMe y un kernel ajustado para
workloads de base de datos — O_DIRECT funciona sin fallback silencioso
y el I/O predecible reduce la necesidad de un buffer pool gigante para
compensar la latencia de un disco lento.
Preguntas frecuentes
¿Cuánta RAM consume MySQL 8 por defecto sin ajustes?
En una instalación estándar de MySQL 8.0 en Ubuntu/Debian, el proceso mysqld ocupa entre 380 y 500 MB de RSS ya en el arranque, sin ninguna conexión activa. Esto proviene principalmente de innodb_buffer_pool_size (128 MB), performance_schema (~80 MB) y tablas mysql.* del sistema. En VPS de 1 GB, esto ya consume ~40% de la RAM antes de cualquier query.
¿Puedo desactivar performance_schema sin romper nada?
Sí, con salvedades. El performance_schema alimenta las vistas sys.* y herramientas como percona-toolkit pt-query-digest. Desactivarlo ahorra 70-100 MB de RAM pero pierdes visibilidad fina de queries lentas. Recomendado en VPS de 1 GB; en 2 GB o más, déjalo activado y ajusta solo los consumers vía setup_consumers.
¿Cuál es el valor ideal para innodb_buffer_pool_size en VPS pequeña?
La regla de 70-80% de la RAM física solo aplica en servidores dedicados a MySQL. En VPS de 1 GB ejecutando MySQL + app web + nginx, deja entre 256 y 384 MB. En VPS de 2 GB, 512 a 768 MB. El resto va para la app, caché del OS y margen contra el OOM killer.
¿Vale la pena desactivar el binary log (log_bin) en VPS pequeña?
Solo desactívalo si NO usas replicación ni point-in-time recovery. El binary log consume IOPS (escritura secuencial) y disco (~10-20% del tráfico de escritura). Sin él, el restore solo vuelve al último mysqldump. Para single-instance con backup diario aceptable, desactivar está bien; para cualquier setup que pueda convertirse en réplica después, mantenlo.
¿Cómo sé si mis ajustes funcionaron?
Ejecuta SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages%' después de 24h de uso real. Si Innodb_buffer_pool_pages_free queda cerca de cero e Innodb_buffer_pool_reads crece rápido, el pool está pequeño. Combina con free -m para confirmar que el sistema no está en swap. El RSS de mysqld en ps aux debe quedar estable tras el warm-up.
¿Puedo usar MariaDB en lugar de MySQL para ahorrar RAM?
MariaDB 10.6+ tiene un footprint similar al MySQL 8.0 — no hay un ahorro mágico. La diferencia real viene del ajuste del my.cnf, no del fork. MariaDB tiene algunos valores por defecto más conservadores (innodb_buffer_pool_size=128M también), así que los mismos ajustes de este tutorial valen con `[mariadb]` en lugar de `[mysqld]` cuando aplica.