--- title: "Cómo optimizar MySQL y MariaDB con my.cnf en Ubuntu 24.04" description: "Ajusta my.cnf en MySQL 8.0 o MariaDB en Ubuntu 24.04: buffer pool de InnoDB, redo log, conexiones y log de consultas lentas, midiendo el efecto de cada cambio." category: "Gestión de Bases de Datos" language: es source: https://cubepath.com/es/docs/gestión-de-bases-de-datos/optimizacion-de-rendimiento-mysql-mariadb-my-cnf updated: 2026-09-25 --- # Cómo optimizar MySQL y MariaDB con my.cnf en Ubuntu 24.04 La configuración por defecto de MySQL y MariaDB está pensada para arrancar en cualquier máquina, no para aprovechar la tuya: por ejemplo, reserva solo 128 MB para la caché de InnoDB. En este tutorial ajustarás los parámetros que más influyen en el rendimiento en un servidor Ubuntu 24.04 dedicado a la base de datos, en un archivo propio que no se pierde al actualizar, y comprobarás el efecto de cada cambio con métricas del propio servidor. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con almacenamiento SSD o NVMe. - MySQL 8.0 o MariaDB 10.11 instalado desde los repositorios de Ubuntu, con tablas InnoDB. - Un usuario no root con privilegios `sudo`. - Una carga de trabajo real o representativa. Ajustar sin tráfico que medir es adivinar. Los ejemplos usan como referencia un servidor con 8 GB de RAM y 4 vCPU dedicado a MySQL. Escala los valores a tu máquina. Si el servidor comparte RAM con una aplicación web, reserva primero la memoria que esa aplicación necesita. ## Paso 1: Medir el punto de partida Antes de cambiar nada, anota los valores actuales para poder comparar. Entra en la consola: ```bash sudo mysql ``` Consulta el tamaño del buffer pool y cuántas lecturas tienen que ir a disco porque la página no estaba en memoria: ```sql SELECT @@innodb_buffer_pool_size / 1024 / 1024 AS buffer_pool_mb; SHOW GLOBAL STATUS WHERE Variable_name IN ('Innodb_buffer_pool_read_requests', 'Innodb_buffer_pool_reads', 'Max_used_connections', 'Threads_created', 'Created_tmp_disk_tables', 'Created_tmp_tables', 'Uptime'); ``` ```output +----------------+ | buffer_pool_mb | +----------------+ | 128.00000000 | +----------------+ +----------------------------------+------------+ | Variable_name | Value | +----------------------------------+------------+ | Created_tmp_disk_tables | 1840 | | Created_tmp_tables | 25310 | | Innodb_buffer_pool_read_requests | 918234551 | | Innodb_buffer_pool_reads | 4120933 | | Max_used_connections | 38 | | Threads_created | 212 | | Uptime | 604800 | +----------------------------------+------------+ ``` Qué mirar: - **Aciertos del buffer pool**: `1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)`. En el ejemplo es 99,55 %. En un servidor bien dimensionado debería estar por encima del 99,9 %. - **`Max_used_connections`**: el pico real de conexiones desde el arranque. Sirve para dimensionar `max_connections`. - **`Created_tmp_disk_tables` frente a `Created_tmp_tables`**: qué parte de las tablas temporales acabó en disco. Estos contadores se acumulan desde el arranque (`Uptime`, en segundos), así que tómalos después de que el servidor lleve un tiempo recibiendo tráfico normal. ## Paso 2: Crear un archivo de configuración propio No edites `/etc/mysql/my.cnf` ni el `mysqld.cnf` del paquete: una actualización puede preguntarte si sobrescribirlos. En su lugar, crea un archivo que se lea el último (por eso el prefijo `zz-`). MySQL carga los archivos de `/etc/mysql/mysql.conf.d/` por orden alfabético y, si una directiva aparece dos veces, gana la última. Para MySQL 8.0: ```bash sudo nano /etc/mysql/mysql.conf.d/zz-tuning.cnf ``` Para MariaDB, el directorio equivalente es `/etc/mysql/mariadb.conf.d/`: ```bash sudo nano /etc/mysql/mariadb.conf.d/zz-tuning.cnf ``` En los pasos siguientes irás completando este archivo. Todas las directivas van bajo la sección `[mysqld]`. ## Paso 3: Dimensionar el buffer pool de InnoDB `innodb_buffer_pool_size` es el parámetro más importante: es la caché donde InnoDB guarda datos e índices. Si tus datos activos caben en él, la mayoría de las lecturas no tocan el disco. En un servidor dedicado, usa entre el 60 % y el 75 % de la RAM. Para saber cuánto ocupan tus datos e índices InnoDB: ```sql SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024 / 1024, 2) AS innodb_gb FROM information_schema.tables WHERE engine = 'InnoDB'; ``` Si el resultado es menor que el 70 % de la RAM, no hace falta que el buffer pool sea mucho mayor que los datos más un margen de crecimiento. Para el servidor de 8 GB de ejemplo: ```ini [mysqld] innodb_buffer_pool_size = 5G ``` MySQL divide automáticamente el buffer pool en varias instancias cuando supera 1 GB, así que no necesitas ajustar `innodb_buffer_pool_instances`. > Nota: en MySQL 8.0 puedes probar el tamaño en caliente con `SET GLOBAL innodb_buffer_pool_size = 5368709120;` sin reiniciar. El cambio se pierde al reiniciar si no lo guardas en el archivo. ## Paso 4: Ajustar el redo log y el vaciado a disco El redo log registra los cambios antes de escribirlos en los archivos de datos. Si es pequeño, InnoDB tiene que vaciar páginas a disco con mucha frecuencia en cargas con muchas escrituras. En MySQL 8.0.30 y posteriores (Ubuntu 24.04 trae 8.0.4x) se controla con un único parámetro: ```ini innodb_redo_log_capacity = 2G innodb_flush_method = O_DIRECT innodb_io_capacity = 1000 innodb_io_capacity_max = 2000 ``` - `innodb_redo_log_capacity`: el valor por defecto es 100 MB. Entre 1 y 2 GB es razonable para una carga con escrituras frecuentes; a cambio, la recuperación tras un corte tarda algo más. - `innodb_flush_method = O_DIRECT`: evita que los datos se guarden dos veces en memoria (en el buffer pool y en la caché de páginas del sistema). Es la opción recomendada en Linux. - `innodb_io_capacity`: las operaciones por segundo que InnoDB usa para las escrituras en segundo plano. El valor por defecto (200) está pensado para discos mecánicos; en SSD o NVMe, 1000 es un punto de partida prudente. En MariaDB 10.11 el redo log se configura con `innodb_log_file_size` en lugar de `innodb_redo_log_capacity`: ```ini innodb_log_file_size = 2G ``` Deja `innodb_flush_log_at_trx_commit` en su valor por defecto (`1`) salvo que aceptes perder hasta un segundo de transacciones confirmadas si el servidor se cae. Con `2` las escrituras son más rápidas, pero ya no es una base de datos completamente duradera. ## Paso 5: Dimensionar las conexiones y las tablas temporales Cada conexión reserva memoria propia para ordenaciones, joins y tablas temporales, así que un `max_connections` demasiado alto puede agotar la RAM en un pico de tráfico. Usa como referencia el `Max_used_connections` del paso 1 con un margen de un 50 %: ```ini max_connections = 200 thread_cache_size = 32 table_open_cache = 4000 tmp_table_size = 64M max_heap_table_size = 64M ``` - `thread_cache_size`: reutiliza hilos en lugar de crear uno por conexión. Si `Threads_created` sigue creciendo rápido con el servidor ya caliente, súbelo. - `table_open_cache`: número de tablas abiertas que se mantienen en caché. Si `Opened_tables` crece continuamente, súbelo. - `tmp_table_size` y `max_heap_table_size`: tamaño máximo de una tabla temporal en memoria (se aplica el menor de los dos, por eso van a la par). Súbelos solo si `Created_tmp_disk_tables` es una proporción alta de `Created_tmp_tables`. No subas por defecto `sort_buffer_size`, `join_buffer_size` ni `read_buffer_size`: se reservan por conexión y valores altos suelen empeorar el rendimiento. Si una consulta concreta los necesita, es mejor añadir un índice. > Nota: si estás en MySQL 5.7 o en MariaDB, verás recomendaciones sobre `query_cache_size`. La caché de consultas no existe en MySQL 8.0 y en MariaDB viene desactivada por defecto porque se convierte en un cuello de botella con varias CPU. Déjala así. ## Paso 6: Activar el log de consultas lentas Ningún parámetro compensa una consulta sin índice. El log de consultas lentas te dice cuáles son: ```ini slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 1 log_queries_not_using_indexes = OFF ``` Con `long_query_time = 1` se registran las consultas que tardan más de un segundo. Puedes bajarlo a `0.5` una vez eliminadas las más lentas. ## Paso 7: Aplicar y verificar la configuración El archivo completo para el servidor de ejemplo con MySQL 8.0 queda así: ```ini [mysqld] # Memoria innodb_buffer_pool_size = 5G # Redo log y E/S innodb_redo_log_capacity = 2G innodb_flush_method = O_DIRECT innodb_io_capacity = 1000 innodb_io_capacity_max = 2000 # Conexiones y tablas max_connections = 200 thread_cache_size = 32 table_open_cache = 4000 tmp_table_size = 64M max_heap_table_size = 64M # Consultas lentas slow_query_log = ON slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 1 log_queries_not_using_indexes = OFF ``` Reinicia el servicio (`mariadb` en lugar de `mysql` si usas MariaDB) y comprueba que ha arrancado: ```bash sudo systemctl restart mysql sudo systemctl status mysql --no-pager ``` Si no arranca, el motivo aparece en el log de errores: ```bash sudo tail -n 30 /var/log/mysql/error.log ``` Confirma que los valores se han aplicado: ```bash sudo mysql -e "SELECT @@innodb_buffer_pool_size/1024/1024/1024 AS bp_gb, @@innodb_redo_log_capacity/1024/1024 AS redo_mb, @@max_connections, @@slow_query_log;" ``` ```output +--------+-----------+-------------------+------------------+ | bp_gb | redo_mb | @@max_connections | @@slow_query_log | +--------+-----------+-------------------+------------------+ | 5.0000 | 2048.0000 | 200 | 1 | +--------+-----------+-------------------+------------------+ ``` ## Paso 8: Analizar las consultas lentas Tras unas horas con tráfico real, resume el log agrupando las consultas similares y ordenándolas por tiempo total: ```bash sudo mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log ``` ```output Count: 1520 Time=2.31s (3511s) Lock=0.00s (0s) Rows=20.0 (30400), miapp_user[miapp_user]@[10.0.0.5] SELECT * FROM orders WHERE customer_email = 'S' ORDER BY created_at DESC LIMIT N ``` Toma la consulta más costosa y revisa su plan de ejecución: ```sql EXPLAIN SELECT * FROM miapp.orders WHERE customer_email = 'cliente@example.com' ORDER BY created_at DESC LIMIT 20; ``` Si la columna `type` muestra `ALL` (recorrido completo de la tabla) y `key` es `NULL`, falta un índice. En este ejemplo: ```sql CREATE INDEX idx_orders_email_created ON miapp.orders (customer_email, created_at); ``` Vuelve a ejecutar el `EXPLAIN` para confirmar que ahora usa el índice (`key` muestra `idx_orders_email_created`). Para una segunda opinión sobre la configuración, `mysqltuner` (disponible en los repositorios de Ubuntu) revisa los contadores del servidor y sugiere ajustes. Úsalo cuando el servidor lleve al menos 24 horas en marcha, y toma sus recomendaciones como puntos a investigar, no como cambios a aplicar sin más: ```bash sudo apt install mysqltuner sudo mysqltuner ``` ## Paso 9: Comparar con el punto de partida Pasados unos días con la nueva configuración, repite las consultas del paso 1 y compara: - La tasa de aciertos del buffer pool debería estar por encima del 99,9 %. Si no, y la RAM lo permite, súbelo. - `Max_used_connections` debe quedar holgadamente por debajo de `max_connections`. - Revisa la memoria del sistema con `free -h`: si el servidor empieza a usar swap, reduce el buffer pool. Una base de datos que hace swap es mucho más lenta que una con menos caché. Cambia un parámetro cada vez y mide antes del siguiente. Si cambias varios a la vez, no sabrás cuál ha tenido efecto. ## Solución de problemas **MySQL no arranca tras el cambio.** Revisa `/var/log/mysql/error.log`. Lo más habitual es una directiva mal escrita (`unknown variable`) o una que no existe en tu servidor, como `innodb_redo_log_capacity` en MariaDB. **El proceso muere con `Out of memory` en `dmesg`.** El buffer pool más la memoria por conexión supera la RAM disponible. Reduce `innodb_buffer_pool_size` o `max_connections`. **`Too many connections`.** Antes de subir `max_connections`, comprueba si la aplicación deja conexiones abiertas o no usa un pool de conexiones. `SHOW PROCESSLIST;` muestra quién las ocupa. ## Conclusión Has pasado de la configuración genérica a una ajustada a tu RAM y tu almacenamiento, en un archivo propio que sobrevive a las actualizaciones, y tienes el log de consultas lentas para encontrar los problemas que ningún parámetro arregla. Como siguientes pasos, puedes analizar el log con más detalle con `pt-query-digest` (paquete `percona-toolkit`), vigilar las métricas de InnoDB con tu sistema de monitorización, y separar lecturas en una réplica si el servidor principal se queda corto.