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:

  1. Verificar logs primero: El log de errores revela la mayoría de los problemas
  2. Verificar conectividad: Asegurar que MySQL está ejecutándose y accesible
  3. Monitorear rendimiento: Consultas lentas y bloqueos causan problemas
  4. Mantenimiento regular: Verificar y optimizar tablas periódicamente
  5. Hacer backups regularmente: La corrupción requiere capacidad de restauración
  6. Monitorear replicación: Detectar retraso antes de que se vuelva crítico
  7. 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.