MySQL avisa de casi todos sus problemas con un código de error y un mensaje concreto, y deja el detalle en su registro de errores. Conocer los códigos más frecuentes y saber dónde mirar reduce una caída de horas a unos minutos. En este tutorial aprenderás a localizar el registro de errores de MySQL 8.0 en Ubuntu 24.04 y a resolver, paso a paso, los errores de conexión, autenticación, límite de conexiones, bloqueos, espacio en disco y corrupción de datos.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS y MySQL 8.0 instalado desde los repositorios de Ubuntu (paquete
mysql-server), por ejemplo en un VPS de CubePath. - Un usuario no root con privilegios
sudo. - Una copia de seguridad reciente de tus bases de datos antes de aplicar cualquier cambio de los pasos 7 y 8.
En Ubuntu, el usuario root de MySQL se autentica por defecto con el complemento auth_socket: sudo mysql entra como administrador sin pedir contraseña. Los comandos de esta guía lo aprovechan. Si has cambiado root a autenticación por contraseña, usa mysql -u root -p en su lugar.
Notacon MariaDB (el servidor por defecto de Debian 12) casi todo es igual, pero el servicio se llama
mariadby algunos comandos de replicación cambian.
Paso 1: Localizar el registro de errores
Cuando algo falla, el primer lugar donde mirar es el registro de errores. Consulta su ruta desde MySQL:
sudo mysql -e "SELECT @@log_error;"
+--------------------------+
| @@log_error |
+--------------------------+
| /var/log/mysql/error.log |
+--------------------------+
Si MySQL no está en marcha y no puedes preguntarle, la ruta está en /etc/mysql/mysql.conf.d/mysqld.cnf, en la directiva log_error. Muestra las últimas líneas:
sudo tail -n 50 /var/log/mysql/error.log
El diario de systemd recoge además los errores de arranque del servicio:
sudo journalctl -u mysql -n 50 --no-pager
Cada línea del registro incluye un nivel ([System], [Warning] o [ERROR]) y un código entre corchetes, como [MY-010958]. Buscar solo los errores filtra el ruido:
sudo grep '\[ERROR\]' /var/log/mysql/error.log | tail -n 20
Paso 2: Resolver el error 2002 (no se puede conectar al socket)
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
El cliente intenta conectar por el socket Unix local y no encuentra al servidor al otro lado. En la inmensa mayoría de los casos, MySQL no está en marcha. Compruébalo:
sudo systemctl status mysql
Si aparece inactive (dead) o failed, intenta arrancarlo y consulta el motivo si falla:
sudo systemctl start mysql
sudo journalctl -u mysql -n 30 --no-pager
sudo tail -n 30 /var/log/mysql/error.log
Las causas de arranque fallido más habituales y el mensaje que dejan en el registro son:
| Mensaje en el registro | Causa | Solución |
|---|---|---|
unknown variable 'xxx' | Error tipográfico o directiva no válida en la configuración. | Corregir o eliminar la línea indicada. |
No space left on device o errno: 28 | Disco lleno. | Liberar espacio (paso 6). |
Unable to lock ./ibdata1 error: 11 | Ya hay otro proceso mysqld usando el directorio de datos. | Localizarlo con pgrep -a mysqld y detenerlo. |
Out of memory en journalctl -k | El núcleo mató a mysqld por falta de RAM. | Reducir innodb_buffer_pool_size o añadir memoria. |
Database page corruption o InnoDB: Assertion failure | Corrupción de datos. | Seguir el paso 8. |
Si MySQL sí está en marcha y el error persiste, el cliente busca el socket en otra ruta. Comprueba dónde lo crea el servidor:
sudo mysql -e "SELECT @@socket;"
Una aplicación que se conecta a localhost usa el socket. Si está configurada con otra ruta, corrige la ruta en la aplicación o conecta por TCP usando 127.0.0.1 en lugar de localhost.
Paso 3: Resolver el error 1045 (acceso denegado)
ERROR 1045 (28000): Access denied for user 'app_user'@'localhost' (using password: YES)
MySQL identifica a cada usuario por la pareja usuario y host. 'app_user'@'localhost' y 'app_user'@'%' son cuentas distintas, con contraseñas distintas. Lista las cuentas que existen:
sudo mysql -e "SELECT user, host, plugin FROM mysql.user ORDER BY user;"
+------------------+-----------+-----------------------+
| user | host | plugin |
+------------------+-----------+-----------------------+
| app_user | 10.0.0.% | caching_sha2_password |
| root | localhost | auth_socket |
+------------------+-----------+-----------------------+
En este ejemplo, app_user solo existe para conexiones desde 10.0.0.%, así que una conexión desde el propio servidor (localhost) se rechaza. Crea la cuenta para el host correcto o, si la contraseña es la que falla, restablécela con un valor seguro:
sudo mysql -e "ALTER USER 'app_user'@'10.0.0.%' IDENTIFIED BY 'your_strong_password';"
Comprueba después que la cuenta tiene permisos sobre la base de datos que usa la aplicación:
sudo mysql -e "SHOW GRANTS FOR 'app_user'@'10.0.0.%';"
Si has perdido la contraseña de root
Si cambiaste root a autenticación por contraseña y la has olvidado, sudo mysql ya no funciona. Detén el servicio y arranca MySQL a mano sin comprobación de permisos y sin red, para que nadie más pueda entrar mientras tanto:
sudo systemctl stop mysql
sudo install -d -o mysql -g mysql /var/run/mysqld
sudo -u mysql /usr/sbin/mysqld --skip-grant-tables --skip-networking &
Conéctate, recarga las tablas de permisos (necesario para poder usar ALTER USER en este modo) y devuelve a root la autenticación por socket de Ubuntu:
sudo mysql -e "FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;"
Detén esa instancia temporal y arranca el servicio normal:
sudo mysqladmin shutdown
sudo systemctl start mysql
Comprueba que sudo mysql -e "SELECT CURRENT_USER();" devuelve root@localhost.
Paso 4: Resolver el error 1040 (demasiadas conexiones)
ERROR 1040 (HY000): Too many connections
El servidor ha alcanzado max_connections (151 por defecto). MySQL reserva una conexión adicional para administradores, así que sudo mysql suele seguir funcionando. Mira cuántas conexiones hay y de quién son:
sudo mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';"
sudo mysql -e "SELECT user, host, command, COUNT(*) AS conexiones FROM information_schema.processlist GROUP BY user, host, command ORDER BY conexiones DESC;"
La columna command explica la causa:
- Muchas conexiones en
Sleep: la aplicación abre conexiones y no las cierra, o su pool es mayor de lo necesario. La solución está en la aplicación; como mitigación, reducewait_timeoutpara que MySQL cierre antes las conexiones inactivas. - Muchas conexiones en
Query: las consultas son lentas y se acumulan. Subir el límite solo empeora la saturación; busca las consultas lentas y los bloqueos (paso 5).
Si el tráfico legítimo realmente necesita más conexiones, sube el límite en caliente y hazlo persistente con SET PERSIST, que MySQL 8 guarda en mysqld-auto.cnf dentro del directorio de datos:
sudo mysql -e "SET PERSIST max_connections = 300;"
Cada conexión consume memoria, así que aumenta el valor de forma gradual y vigila la RAM libre.
Paso 5: Resolver bloqueos (errores 1205 y 1213)
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
El error 1205 aparece cuando una transacción espera más de innodb_lock_wait_timeout (50 segundos por defecto) a que otra libere una fila. El esquema sys de MySQL 8 muestra quién bloquea a quién:
sudo mysql -e "SELECT waiting_pid, waiting_query, blocking_pid, blocking_query, wait_age FROM sys.innodb_lock_waits\G"
*************************** 1. row ***************************
waiting_pid: 3187
waiting_query: UPDATE pedidos SET estado = 'enviado' WHERE id = 1042
blocking_pid: 3150
blocking_query: NULL
wait_age: 00:00:41
Un blocking_query en NULL indica una transacción abierta que ya terminó su consulta pero no ha hecho COMMIT, por ejemplo una sesión olvidada en una consola o un proceso de la aplicación colgado. Si confirmas que se puede cancelar, termina esa conexión y su transacción se deshará:
sudo mysql -e "KILL 3150;"
El error 1213 (interbloqueo) lo resuelve MySQL por sí mismo cancelando una de las dos transacciones. La aplicación debe reintentar la transacción cancelada. Para ver cuál fue el último interbloqueo y qué filas implicaba:
sudo mysql -e "SHOW ENGINE INNODB STATUS\G" | sed -n '/LATEST DETECTED DEADLOCK/,/TRANSACTIONS/p'
Los interbloqueos frecuentes se reducen con transacciones cortas, índices en las columnas del WHERE (para bloquear menos filas) y accediendo a las tablas siempre en el mismo orden.
Paso 6: Resolver el error de disco lleno (errno 28)
ERROR 3 (HY000): Error writing file '/tmp/MYfd=12' (OS errno 28 - No space left on device)
Comprueba el espacio del volumen de datos y del directorio temporal:
df -h /var/lib/mysql /tmp
Localiza qué ocupa el espacio dentro del directorio de datos:
sudo du -sh /var/lib/mysql/* | sort -h | tail -n 10
Si lo que más ocupa son los archivos binlog.000NNN, son los registros binarios. MySQL 8 los activa por defecto y los conserva 30 días. Nunca los borres con rm: MySQL mantiene un índice de ellos y dejaría de arrancar o de replicar correctamente. Consulta cuáles hay y purga los antiguos desde MySQL:
sudo mysql -e "SHOW BINARY LOGS;"
sudo mysql -e "PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;"
Advertenciasi el servidor tiene réplicas, comprueba antes con
SHOW REPLICA STATUSen cada una que ya han leído los registros que vas a purgar.
Para que no vuelva a ocurrir, reduce la retención de forma permanente, por ejemplo a 7 días:
sudo mysql -e "SET PERSIST binlog_expire_logs_seconds = 604800;"
Si lo que crece es una tabla concreta, revisa qué tablas son las más grandes:
sudo mysql -e "SELECT table_schema, table_name, ROUND((data_length + index_length)/1024/1024) AS mb FROM information_schema.tables ORDER BY mb DESC LIMIT 10;"
Paso 7: Resolver errores de datos y de tablas
Error 1062 (entrada duplicada)
ERROR 1062 (23000): Duplicate entry '[email protected]' for key 'usuarios.email'
Una clave única ya contiene ese valor. Es un error de la aplicación o de los datos importados, no del servidor. Para encontrar los duplicados existentes antes de crear un índice único:
sudo mysql your_database -e "SELECT email, COUNT(*) AS n FROM usuarios GROUP BY email HAVING n > 1;"
Error 1406 (datos demasiado largos)
ERROR 1406 (22001): Data too long for column 'nombre' at row 1
MySQL 8 trabaja por defecto en modo estricto y rechaza los valores que no caben en la columna en lugar de recortarlos. Comprueba la definición de la columna y amplíala si el dato es legítimo:
sudo mysql your_database -e "SHOW CREATE TABLE clientes\G"
sudo mysql your_database -e "ALTER TABLE clientes MODIFY nombre VARCHAR(255) NOT NULL;"
Desactivar el modo estricto oculta el problema y provoca pérdida silenciosa de datos, así que evítalo.
Error 1146 (la tabla no existe)
ERROR 1146 (42S02): Table 'tienda.Pedidos' doesn't exist
En Linux, los nombres de tabla distinguen entre mayúsculas y minúsculas. Lista las tablas y compara el nombre exacto:
sudo mysql tienda -e "SHOW TABLES;"
Si la tabla se llama pedidos, corrige la consulta de la aplicación. En MySQL 8, lower_case_table_names solo puede fijarse al inicializar el servidor, así que no lo cambies en una instalación existente.
Comprobar tablas dañadas
mysqlcheck revisa todas las tablas de todas las bases de datos:
sudo mysqlcheck --all-databases --check
tienda.clientes OK
tienda.pedidos OK
Para tablas MyISAM marcadas como dañadas (error 145), REPAIR TABLE las reconstruye:
sudo mysql your_database -e "REPAIR TABLE nombre_tabla;"
REPAIR TABLE no funciona con InnoDB, el motor por defecto. Una tabla InnoDB dañada se recupera volcándola y restaurándola, como se explica en el paso siguiente.
Paso 8: Recuperar un servidor InnoDB que no arranca
Si el registro de errores muestra corrupción de páginas o un Assertion failure de InnoDB y MySQL no arranca, lo primero es proteger lo que queda. Detén el servicio y copia el directorio de datos completo:
sudo systemctl stop mysql
sudo cp -a /var/lib/mysql /var/lib/mysql.bak-$(date +%F)
Si tienes una copia de seguridad reciente, restaurarla es casi siempre la opción más segura. Si no, innodb_force_recovery permite arrancar MySQL en un modo degradado para extraer los datos. Añádelo a la sección [mysqld]:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
innodb_force_recovery = 1
Intenta arrancar:
sudo systemctl start mysql
Si sigue sin arrancar, sube el valor de uno en uno (2, 3...) y vuelve a intentarlo. Los valores 1 a 3 son relativamente seguros; a partir de 4 InnoDB puede dejar los archivos en un estado del que no hay vuelta atrás, y por eso has hecho la copia anterior. En este modo las tablas son de solo lectura. En cuanto MySQL arranque, vuelca todas las bases de datos:
sudo mysqldump --all-databases --routines --events --single-transaction > ~/recuperacion-$(date +%F).sql
Después elimina la línea innodb_force_recovery de mysqld.cnf. Con el volcado a salvo, lo habitual es reinicializar MySQL con un directorio de datos limpio e importar el volcado. Revisa las tablas que hayan dado error durante el mysqldump: son las que tendrás que recuperar desde una copia de seguridad.
Solución de problemas
systemctl start mysql falla sin nada en error.log: el fallo es anterior a que MySQL abra su registro, normalmente un error de sintaxis en la configuración o un permiso. Ejecuta sudo -u mysql /usr/sbin/mysqld --validate-config para comprobar la configuración y revisa sudo journalctl -u mysql.
ERROR 2003 (HY000): Can't connect to MySQL server on 'your_server_ip:3306': la conexión remota no llega. MySQL en Ubuntu escucha solo en 127.0.0.1 (bind-address en mysqld.cnf) y el cortafuegos puede bloquear el puerto 3306. Si necesitas acceso remoto, cambia bind-address, permite el puerto solo desde la IP del cliente (sudo ufw allow from client_ip to any port 3306) y crea el usuario para ese host.
Plugin 'mysql_native_password' is not loaded: aparece si actualizas a MySQL 8.4 (por ejemplo, desde el repositorio de Oracle) y una cuenta antigua usa ese método, que 8.4 ya no carga por defecto. Cámbiala a caching_sha2_password con ALTER USER ... IDENTIFIED WITH caching_sha2_password BY 'your_strong_password'.
Conclusión
Has aprendido a localizar el registro de errores de MySQL y a resolver los fallos más frecuentes: el servicio caído detrás del error 2002, los accesos denegados por la pareja usuario y host, el límite de conexiones, los bloqueos entre transacciones, el disco lleno por registros binarios y la recuperación de un servidor InnoDB dañado. Como siguientes pasos, programa copias de seguridad diarias con mysqldump o Percona XtraBackup y comprueba que se pueden restaurar, activa el registro de consultas lentas para detectar problemas antes de que provoquen errores, y vigila el espacio libre en /var/lib/mysql.
