Errores de MySQL: Diagnóstico y Soluciones
Introducción
Los errores de bases de datos MySQL pueden detener aplicaciones enteras, causando pérdida de datos, interrupciones de servicio y usuarios frustrados. Desde fallos de conexión y tablas corruptas hasta problemas de replicación y problemas de rendimiento, los errores de MySQL requieren diagnóstico rápido y resolución para minimizar el tiempo de inactividad y mantener la integridad de los datos.
Esta guía completa proporciona a los administradores de bases de datos enfoques sistemáticos para diagnosticar y resolver errores de MySQL. Aprenderás a interpretar mensajes de error, usar herramientas de diagnóstico, analizar logs e implementar soluciones para problemas comunes de MySQL que afectan tanto instalaciones de MariaDB como MySQL.
Comprender el diagnóstico de errores de MySQL es crítico para cualquiera que gestione aplicaciones basadas en bases de datos. Esta guía cubre todo, desde solución de problemas básicos de conexión hasta procedimientos avanzados de recuperación para bases de datos corruptas, permitiéndote restaurar rápidamente la funcionalidad de la base de datos.
Comprendiendo los Errores de MySQL
Categorías Comunes de Errores
Errores de Conexión: No se puede conectar al servidor MySQL Errores de Permisos: Acceso denegado para usuario Errores de Datos: Entrada duplicada, truncamiento de datos Errores de Tabla: La tabla no existe, tabla marcada como dañada Errores de Replicación: Retraso de esclavo, replicación detenida Errores de Rendimiento: Demasiadas conexiones, timeout de espera de bloqueo Errores de Almacenamiento: Disco lleno, tablespace lleno
Ubicación del Log de Errores de MySQL
# Encontrar ubicación del log de errores
mysql -e "SHOW VARIABLES LIKE 'log_error';"
# Ubicaciones comunes
tail -100 /var/log/mysql/error.log # Debian/Ubuntu
tail -100 /var/log/mysqld.log # CentOS/RHEL
tail -100 /var/lib/mysql/$(hostname).err # Predeterminado
# Verificar con systemd
journalctl -u mysql -n 100
journalctl -u mariadb -n 100
Diagnóstico Inicial de MySQL
Verificación Rápida de Estado
# Verificar servicio MySQL
systemctl status mysql
systemctl status mariadb
# Intentar conectar
mysql -u root -p
# Verificar si MySQL está escuchando
ss -tlnp | grep mysql
ss -tlnp | grep 3306
# Verificar proceso
ps aux | grep mysqld
# Estado rápido
mysqladmin -u root -p status
mysqladmin -u root -p ping
# Número de conexiones
mysqladmin -u root -p processlist
# Variables
mysql -e "SHOW VARIABLES LIKE 'version%';"
Paso 1: Errores de Conexión
Error: No Puede Conectar al Servidor MySQL
# Mensaje de error:
# ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'
# Verificar si MySQL está ejecutándose
systemctl status mysql
# Iniciar si está detenido
systemctl start mysql
# Verificar archivo socket
ls -la /var/run/mysqld/mysqld.sock
ls -la /tmp/mysql.sock
# Encontrar ubicación del socket
mysql -e "SHOW VARIABLES LIKE 'socket';"
# Verificar my.cnf
grep socket /etc/mysql/my.cnf
grep socket /etc/my.cnf
# Verificar permisos del socket
ls -l /var/run/mysqld/
# Corregir permisos
chown mysql:mysql /var/run/mysqld
chmod 755 /var/run/mysqld
Error: Acceso Denegado
# ERROR 1045 (28000): Access denied for user 'root'@'localhost'
# Restablecer contraseña de root
systemctl stop mysql
# Iniciar en modo seguro
mysqld_safe --skip-grant-tables &
# Conectar sin contraseña
mysql -u root
# Restablecer contraseña
mysql> FLUSH PRIVILEGES;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'nuevacontraseña';
mysql> exit
# Reiniciar normalmente
killall mysqld
systemctl start mysql
# Probar nueva contraseña
mysql -u root -p
# Verificar permisos de usuario
mysql -e "SELECT user, host FROM mysql.user;"
mysql -e "SHOW GRANTS FOR 'usuario'@'localhost';"
Error: Demasiadas Conexiones
# ERROR 1040 (HY000): Too many connections
# Verificar conexiones actuales
mysql -e "SHOW PROCESSLIST;"
mysql -e "SHOW STATUS LIKE 'Threads_connected';"
# Verificar max connections
mysql -e "SHOW VARIABLES LIKE 'max_connections';"
# Matar conexión específica
mysql -e "KILL connection_id;"
# Aumentar max_connections temporalmente
mysql -e "SET GLOBAL max_connections = 500;"
# Corrección permanente - editar my.cnf
[mysqld]
max_connections = 500
# Reiniciar MySQL
systemctl restart mysql
# Encontrar usuarios con muchas conexiones
mysql -e "SELECT user, COUNT(*) as connections
FROM information_schema.PROCESSLIST
GROUP BY user
ORDER BY connections DESC;"
Paso 2: Errores de Tabla
Error: Tabla Marcada como Dañada
# ERROR 145 (HY000): Table './database/table' is marked as crashed
# Verificar tabla
mysql -e "CHECK TABLE database.table;"
# Reparar tabla
mysql -e "REPAIR TABLE database.table;"
# Forzar reparación
mysql -e "REPAIR TABLE database.table EXTENDED;"
# Usar myisamchk (para tablas MyISAM - el servicio debe estar detenido)
systemctl stop mysql
myisamchk -r /var/lib/mysql/database/table.MYI
systemctl start mysql
# Para corrupción de InnoDB
mysql -e "SELECT * FROM database.table INTO OUTFILE '/tmp/table_backup.txt';"
mysql -e "DROP TABLE database.table;"
# Restaurar desde backup
# Verificar todas las tablas
mysqlcheck -u root -p --all-databases
mysqlcheck -u root -p --auto-repair --all-databases
Error: La Tabla No Existe
# ERROR 1146 (42S02): Table 'database.table' doesn't exist
# Listar tablas
mysql -e "SHOW TABLES FROM database;"
# Verificar sensibilidad a mayúsculas/minúsculas
mysql -e "SHOW VARIABLES LIKE 'lower_case_table_names';"
# Verificar directorio de datos
ls -la /var/lib/mysql/database/
# Recuperar desde archivo .frm
mysql database < table.frm
# Si existe archivo .ibd (InnoDB)
# Editar my.cnf
[mysqld]
innodb_force_recovery = 1
systemctl restart mysql
# Exportar datos
mysqldump -u root -p database > backup.sql
# Eliminar force recovery
# Editar my.cnf, eliminar innodb_force_recovery
systemctl restart mysql
Paso 3: Errores de Datos
Error: Entrada Duplicada
# ERROR 1062 (23000): Duplicate entry 'value' for key 'PRIMARY'
# Encontrar duplicados
mysql -e "SELECT column, COUNT(*)
FROM database.table
GROUP BY column
HAVING COUNT(*) > 1;"
# Eliminar duplicados
# Método 1: Mantener primera ocurrencia
CREATE TABLE temp_table AS
SELECT DISTINCT * FROM original_table;
DROP TABLE original_table;
RENAME TABLE temp_table TO original_table;
# Método 2: Eliminar duplicados
DELETE t1 FROM table t1
INNER JOIN table t2
WHERE t1.id > t2.id
AND t1.duplicate_column = t2.duplicate_column;
# Verificar restricciones
mysql -e "SHOW CREATE TABLE database.table\G"
Error: Datos Demasiado Largos
# ERROR 1406 (22001): Data too long for column
# Verificar definición de columna
mysql -e "DESCRIBE database.table;"
# Modificar tamaño de columna
mysql -e "ALTER TABLE database.table
MODIFY column_name VARCHAR(500);"
# Para tipos TEXT
mysql -e "ALTER TABLE database.table
MODIFY column_name MEDIUMTEXT;"
# Verificar tamaño máximo de paquete
mysql -e "SHOW VARIABLES LIKE 'max_allowed_packet';"
# Aumentar si es necesario
mysql -e "SET GLOBAL max_allowed_packet = 67108864;" # 64MB
# Permanente en my.cnf
[mysqld]
max_allowed_packet = 64M
Paso 4: Errores de Replicación
Verificar Estado de Replicación
# En slave/réplica
mysql -e "SHOW SLAVE STATUS\G"
# Campos clave a verificar:
# - Slave_IO_Running: Debe ser "Yes"
# - Slave_SQL_Running: Debe ser "Yes"
# - Last_Error: Muestra mensaje de error
# - Seconds_Behind_Master: Retraso en segundos
# En master
mysql -e "SHOW MASTER STATUS\G"
mysql -e "SHOW BINARY LOGS;"
Corregir Replicación
# Saltar un error
mysql -e "SET GLOBAL sql_slave_skip_counter = 1;"
mysql -e "START SLAVE;"
# Restablecer slave
mysql -e "STOP SLAVE;"
mysql -e "RESET SLAVE;"
# Reconfigurar slave
mysql -e "CHANGE MASTER TO
MASTER_HOST='master_ip',
MASTER_USER='repl_user',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=12345;"
mysql -e "START SLAVE;"
# Verificar estado
mysql -e "SHOW SLAVE STATUS\G"
# Monitorear retraso de replicación
watch -n 1 "mysql -e 'SHOW SLAVE STATUS\G' | grep Seconds_Behind_Master"
Paso 5: Errores de Rendimiento
Timeout de Espera de Bloqueo
# ERROR 1205 (HY000): Lock wait timeout exceeded
# Mostrar bloqueos actuales
mysql -e "SHOW ENGINE INNODB STATUS\G" | grep -A 20 "TRANSACTIONS"
# Encontrar consultas bloqueantes
mysql -e "SELECT * FROM information_schema.INNODB_TRX;"
mysql -e "SELECT * FROM information_schema.INNODB_LOCKS;"
mysql -e "SELECT * FROM information_schema.INNODB_LOCK_WAITS;"
# Matar consulta bloqueante
mysql -e "KILL query_id;"
# Aumentar timeout
mysql -e "SET GLOBAL innodb_lock_wait_timeout = 120;"
# En my.cnf
[mysqld]
innodb_lock_wait_timeout = 120
# Prevenir transacciones de larga duración
mysql -e "SELECT * FROM information_schema.PROCESSLIST
WHERE TIME > 60
ORDER BY TIME DESC;"
Consultas Lentas
# Habilitar slow query log
mysql -e "SET GLOBAL slow_query_log = 'ON';"
mysql -e "SET GLOBAL long_query_time = 2;"
# Verificar ubicación del slow query log
mysql -e "SHOW VARIABLES LIKE 'slow_query_log_file';"
# Analizar consultas lentas
mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log
# Encontrar consultas lentas actuales
mysql -e "SELECT * FROM information_schema.PROCESSLIST
WHERE TIME > 5
ORDER BY TIME DESC;"
# Explicar consulta lenta
mysql -e "EXPLAIN SELECT * FROM table WHERE condition;"
# Agregar índices
mysql -e "ALTER TABLE table ADD INDEX idx_column (column);"
# Optimizar tablas
mysql -e "OPTIMIZE TABLE database.table;"
Paso 6: Errores de Almacenamiento
Error de Disco Lleno
# ERROR 3 (HY000): Error writing file (errno: 28 - No space left on device)
# Verificar espacio en disco
df -h /var/lib/mysql
# Encontrar archivos grandes
du -sh /var/lib/mysql/* | sort -rh | head -20
# Limpiar binary logs
mysql -e "SHOW BINARY LOGS;"
mysql -e "PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;"
# Limpiar relay logs
mysql -e "PURGE RELAY LOGS BEFORE NOW() - INTERVAL 3 DAY;"
# Eliminar backups antiguos
find /var/backups/mysql -name "*.sql" -mtime +7 -delete
# Configurar expiración de binary log
# En my.cnf
[mysqld]
expire_logs_days = 7
max_binlog_size = 100M
Problemas de Tablespace de InnoDB
# ERROR 1114 (HY000): The table 'table' is full
# Verificar tablespace
mysql -e "SELECT tablespace_name, file_name, total_extents
FROM information_schema.FILES
WHERE file_type = 'TABLESPACE';"
# Expandir tablespace
mysql -e "ALTER TABLESPACE tablespace_name
ADD DATAFILE '/path/to/datafile.ibd'
INITIAL_SIZE=1G;"
# Habilitar tablespaces por tabla
# En my.cnf
[mysqld]
innodb_file_per_table = 1
# Verificar tamaño de archivo InnoDB
du -sh /var/lib/mysql/ibdata1
Paso 7: Recuperación de Corrupción
Recuperación de Crasheo de InnoDB
# InnoDB no inicia - habilitar modo de recuperación
# Editar /etc/mysql/my.cnf
[mysqld]
innodb_force_recovery = 1
# Niveles de recuperación:
# 1 = Permitir que el servidor funcione incluso si detecta página corrupta
# 2 = Prevenir operaciones de thread maestro
# 3 = No ejecutar rollbacks de transacción
# 4 = No calcular estadísticas de tabla
# 5 = No mirar undo logs
# 6 = No hacer rollback hacia adelante
# Reiniciar MySQL
systemctl restart mysql
# Volcar bases de datos
mysqldump -u root -p --all-databases > all_databases.sql
# Eliminar modo de recuperación
# Editar my.cnf, eliminar innodb_force_recovery
systemctl restart mysql
# Restaurar si es necesario
mysql -u root -p < all_databases.sql
Verificaciones Generales de Corrupción
# Verificar todas las bases de datos
mysqlcheck -u root -p --all-databases
# Verificar y reparar
mysqlcheck -u root -p --auto-repair --all-databases
# Optimizar todas las tablas
mysqlcheck -u root -p --optimize --all-databases
# Analizar tablas
mysqlcheck -u root -p --analyze --all-databases
Soluciones y Prevención
Optimización de Configuración
# Configuraciones recomendadas de my.cnf
[mysqld]
# Configuraciones de conexión
max_connections = 200
max_connect_errors = 1000000
# Configuraciones de buffer
innodb_buffer_pool_size = 4G # 70-80% de RAM
innodb_log_file_size = 256M
innodb_log_buffer_size = 16M
# Query cache (deshabilitado en MySQL 8.0+)
query_cache_size = 0
query_cache_type = 0
# Configuraciones de timeout
wait_timeout = 600
interactive_timeout = 600
lock_wait_timeout = 60
# Configuraciones de binary log
expire_logs_days = 7
max_binlog_size = 100M
sync_binlog = 1
# Registro de errores
log_error = /var/log/mysql/error.log
log_warnings = 2
# Slow query logging
slow_query_log = 1
long_query_time = 2
slow_query_log_file = /var/log/mysql/slow-query.log
Script de Monitoreo
cat > /usr/local/bin/mysql-monitor.sh << 'EOF'
#!/bin/bash
LOG="/var/log/mysql-monitor.log"
ALERT_EMAIL="[email protected]"
# Verificar si MySQL está ejecutándose
if ! systemctl is-active --quiet mysql; then
echo "$(date): MySQL está caído!" >> "$LOG"
systemctl start mysql
echo "MySQL estaba caído y ha sido reiniciado" | \
mail -s "Alerta de MySQL" "$ALERT_EMAIL"
fi
# Verificar conexiones
CONN=$(mysql -e "SHOW STATUS LIKE 'Threads_connected';" | awk '{print $2}' | tail -1)
MAX=$(mysql -e "SHOW VARIABLES LIKE 'max_connections';" | awk '{print $2}' | tail -1)
PERCENT=$((CONN * 100 / MAX))
if [ $PERCENT -gt 80 ]; then
echo "$(date): Conexiones altas: $CONN/$MAX ($PERCENT%)" >> "$LOG"
fi
# Verificar slow queries
SLOW=$(mysql -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';" | awk '{print $2}' | tail -1)
if [ $SLOW -gt 100 ]; then
echo "$(date): Alto número de consultas lentas: $SLOW" >> "$LOG"
fi
# Verificar replicación (si es slave)
if mysql -e "SHOW SLAVE STATUS\G" > /dev/null 2>&1; then
STATUS=$(mysql -e "SHOW SLAVE STATUS\G")
if ! echo "$STATUS" | grep -q "Slave_IO_Running: Yes"; then
echo "$(date): IO de Slave no ejecutándose!" >> "$LOG"
echo "IO de Replicación MySQL detenido" | \
mail -s "Alerta de Replicación MySQL" "$ALERT_EMAIL"
fi
fi
EOF
chmod +x /usr/local/bin/mysql-monitor.sh
echo "*/5 * * * * /usr/local/bin/mysql-monitor.sh" | crontab -
Estrategia de Backup
# Script de backup diario
cat > /usr/local/bin/mysql-backup.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/var/backups/mysql"
DATE=$(date +%Y%m%d-%H%M%S)
RETENTION_DAYS=7
mkdir -p "$BACKUP_DIR"
# Backup de todas las bases de datos
mysqldump -u root -p"password" --all-databases --single-transaction \
--routines --triggers --events > "$BACKUP_DIR/all-databases-$DATE.sql"
# Comprimir backup
gzip "$BACKUP_DIR/all-databases-$DATE.sql"
# Eliminar backups antiguos
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
echo "$(date): Backup completado: all-databases-$DATE.sql.gz"
EOF
chmod +x /usr/local/bin/mysql-backup.sh
echo "0 2 * * * /usr/local/bin/mysql-backup.sh" | crontab -
Conclusión
El diagnóstico de errores de MySQL requiere comprender mensajes de error, análisis de logs y solución sistemática de problemas. Puntos clave:
- Verificar logs primero: El log de errores revela la mayoría de los problemas
- Verificar conectividad: Asegurar que MySQL está ejecutándose y accesible
- Monitorear rendimiento: Consultas lentas y bloqueos causan problemas
- Mantenimiento regular: Verificar y optimizar tablas periódicamente
- Hacer backups regularmente: La corrupción requiere capacidad de restauración
- Monitorear replicación: Detectar retraso antes de que se vuelva crítico
- Configurar apropiadamente: Configuraciones adecuadas previenen muchos errores
Comprender estas técnicas de diagnóstico e implementar monitoreo proactivo asegura operación confiable de MySQL y recuperación rápida cuando ocurren errores.


