Pocos incidentes generan tanta tensión en un departamento de TI como reiniciar un servidor tras un corte eléctrico o un kernel panic y descubrir que el servicio de base de datos no puede iniciar: Job for mariadb.service failed o [ERROR] [InnoDB] Database was not shut down normally!.
A diferencia del motor antiguo MyISAM (que permitía reparaciones rápidas con myisamchk), el motor InnoDB es un sistema de almacenamiento transaccional complejo basado en árboles B+, páginas de espacio de tablas (archivos .ibd e ibdata1) y un registro de doble escritura (doublewrite buffer). Si el servidor se apaga mientras se vaciaban páginas de memoria a disco, el número de secuencia de log (LSN) queda desincronizado y el motor aborta el arranque para evitar escribir sobre datos inconsistentes. Si gestionas este servidor de datos como máquina virtual, recuerda respaldar siempre el volumen subyacente hacia un almacenamiento NFS en Synology y monitorizar caídas mediante nuestra Guía de monitorización SIEM con Wazuh.
// EJECUCIÓN RÁPIDA (TL;DR) – PROCEDIMIENTO DE RESCATE EN 4 PASOS
# 1. COPIA FORENSE OBLIGATORIA (Regla de oro: nunca toques datos sin respaldo crudo):
cp -rp /var/lib/mysql /var/lib/mysql_backup_urgente
# 2. Habilitar modo rescate en /etc/mysql/my.cnf (bajo la sección [mysqld]):
innodb_force_recovery = 1
# 3. Iniciar el servicio y exportar TODO el contenido a un script SQL plano:
systemctl start mariadb && mysqldump -u root -p --all-databases --quick > rescate_total.sql
Si con el nivel 1 no arranca, incrementa progresivamente a 2, 3 hasta un máximo de 6.
1. Inspección Forense del Registro de Errores
Antes de aplicar medidas invasivas, analiza el archivo de registro para identificar el tipo exacto de corrupción física o lógica:
# En Debian / Ubuntu:
tail -n 60 /var/log/mysql/error.log
# En RHEL / AlmaLinux / CentOS:
tail -n 60 /var/log/mariadb/mariadb.log
Los mensajes de alerta más habituales que indican la necesidad de activar el modo de recuperación forzada son:
InnoDB: Page [page id: space=X, page number=Y] log sequence number is in the future!InnoDB: Assertion failure in file btr0pcur.cc(Corrupción en el índice B-Tree de una tabla).InnoDB: Database was not shut down normally! Starting crash recovery.seguido de un cierre inmediato del proceso (signal 6 o 11).
2. La Escala de Niveles de ‘innodb_force_recovery’
La directiva innodb_force_recovery acepta valores enteros del 1 al 6. Cada nivel superior incluye todas las omisiones de seguridad de los niveles inferiores. Su único propósito es permitir que el motor levante en modo lectura para que puedas volcar los datos con mysqldump. Nunca debes permitir que una aplicación en producción escriba datos con este parámetro activo.
| Nivel | Acción Técnica del Motor | Riesgo / Impacto |
|---|---|---|
| 1 (SRV_FORCE_IGNORE_CORRUPT) | Ignora las páginas de datos dañadas que detecte y permite al servidor arrancar saltándose esos bloques. | Bajo (Ideal como primer intento). |
| 2 (SRV_FORCE_NO_BACKGROUND) | Detiene el hilo principal del kernel de InnoDB. Evita que la purga del buffer de transacciones cause un crash. | Bajo. |
| 3 (SRV_FORCE_NO_TRX_UNDO) | No ejecuta la reversión (rollback) de las transacciones incompletas que estaban activas antes de la caída. | Medio (Las transacciones no confirmadas se descartan). |
| 4 (SRV_FORCE_NO_IBUF_MERGE) | Evita la fusión de inserciones en el buffer de índices secundarios. No calcula estadísticas de tablas. | Alto (Riesgo de corrupción en índices secundarios). |
| 5 (SRV_FORCE_NO_UNDO_LOG_SCAN) | Ignora por completo los logs de deshacer (Undo Logs) durante el arranque. Trata las transacciones como confirmadas. | Muy Alto (Inconsistencia lógica de datos). |
| 6 (SRV_FORCE_NO_LOG_REDO) | Omite totalmente la reproducción del log de rehacer (Redo Log). Deja las páginas de datos en su estado físico en disco. | Crítico (Último recurso antes de restaurar backup). |
3. Procedimiento de Rescate Paso a Paso
Paso 1: Configurar el archivo ‘my.cnf’
Abre el archivo de configuración del servicio con privilegios root:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
# O en MySQL estándar: sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Localiza la sección [mysqld] y añade la directiva en nivel 1:
[mysqld]
innodb_force_recovery = 1
Intenta arrancar el servicio: sudo systemctl start mariadb o sudo systemctl start mysql.
Si el servicio sigue fallando en el arranque, sube el valor a 2, guarda e intenta de nuevo. Repite sucesivamente hasta que el demonio consiga iniciar.
Paso 2: Extraer el volcado completo de bases de datos
En el momento en que MySQL consiga arrancar, la base de datos estará en modo de solo lectura. No intentes reparar tablas in situ con OPTIMIZE TABLE ni REPAIR TABLE (InnoDB no las soporta en este estado). Ejecuta inmediatamente:
mysqldump -u root -p --all-databases --force --quick --hex-blob --events --routines --triggers > /var/backups/rescate_completo.sql
El parámetro --force es indispensable: garantiza que si el volcado encuentra una tabla con páginas totalmente destruidas, registrará el error y continuará volcando el resto de las tablas y esquemas de la base de datos sin abortar.
4. Reconstrucción Total del Directorio de Datos
Una vez que tienes el archivo rescate_completo.sql a salvo en disco, el entorno de base de datos dañado debe ser destruido y reinstalado desde cero para garantizar que no queden páginas corruptas en ibdata1:
- Detén el servicio:
sudo systemctl stop mariadb. - Elimina la directiva
innodb_force_recoveryo comenta la línea en el archivo de configuraciónmy.cnf. - Mueve el directorio corrupto a una ubicación de contingencia:
sudo mv /var/lib/mysql /var/lib/mysql_corrupto_old - Crea el directorio limpio con los permisos del sistema correctos:
sudo mkdir /var/lib/mysql && sudo chown -R mysql:mysql /var/lib/mysql - Inicializa el sistema de tablas del sistema limpio:
# En MariaDB: sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysqlEn MySQL 8+:sudo mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql - Arranca el servicio de base de datos limpio:
sudo systemctl start mariadb - Restaura el archivo SQL rescatado:
mysql -u root -p < /var/backups/rescate_completo.sql - Ejecuta la actualización de privilegios y esquemas del sistema:
sudo mysql_upgrade -u root -p --force
Prevención y Resiliencia en Arquitecturas de Producción
La corrupción de InnoDB casi siempre está vinculada a cortes abruptos de energía en servidores sin SAI/UPS o a bloqueos de I/O en hipervisores de virtualización mal configurados. Si tus bases de datos se ejecutan en microservicios, asegúrate de que el contenedor de la base de datos no sea terminado violentamente por el kernel debido a un error OOMKilled (Exit Code 137) y valida que tus aplicaciones web gestionen adecuadamente la cola de peticiones tras nuestro Reverse Proxy NGINX.
Preguntas Frecuentes
¿Por qué recibo el error “Can’t create table (errno: 140)” al restaurar?
Ocurre si estás intentando restaurar sobre una base de datos donde aún existen archivos residuales .ibd en el sistema de archivos del sistema operativo. Reconstruir el directorio /var/lib/mysql limpio desde cero elimina este conflicto de forma definitiva.
¿Se pueden rescatar tablas individuales si solo una está corrupta?
Sí, si tu configuración tiene habilitado innodb_file_per_table = 1 (el estándar desde hace años). Puedes descartar el tablespace de una tabla vacía mediante ALTER TABLE nombre_tabla DISCARD TABLESPACE;, copiar el archivo .ibd recuperado al directorio de la base de datos y vincularlo ejecutando ALTER TABLE nombre_tabla IMPORT TABLESPACE;.
Manual técnico de administración de bases de datos relacionales y recuperación de desastres elaborado por Gustavo Dulcey, Ingeniero de Sistemas especializado en Infraestructura de Datos y Rendimiento de Motores SQL.