Restablecer la contraseña de root de MySQL y MariaDB

Publicado el 17 min de lectura

¿Contraseña de root olvidada? Muchas veces no hace falta ninguna. Y si hace falta, así abres la base de datos durante un minuto justo, sin dejarla a merced de medio internet.

La contraseña de root de la base de datos es una de esas contraseñas que se definen una sola vez durante la instalación y que después no vuelves a necesitar, porque todas las aplicaciones trabajan con sus propias cuentas. Hasta el día en que sí hace falta. Y entonces aparece esto:

ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

La respuesta habitual en internet es: parar el servicio, arrancarlo con --skip-grant-tables, definir la contraseña y listo. Es correcto, pero solo cuenta la mitad de la historia. En esta guía verás además por qué el comando que todo el mundo copia no surte ningún efecto en Ubuntu con MySQL 8, por qué en muchos casos no necesitas ninguna contraseña, y qué hacer si después el servicio ya no arranca.

Comprueba primero: es probable que no necesites ninguna contraseña

En Debian y Ubuntu, el root de la base de datos lleva años sin estar protegido por una contraseña, sino por la identidad del usuario del sistema. MariaDB llama a ese mecanismo unix_socket y MySQL lo llama auth_socket. Vienen a ser lo mismo: quien se conecta a través del socket local y en el sistema operativo ya es root, entra sin contraseña. El razonamiento es sencillo, porque un usuario root del sistema llega de todas formas a todos los archivos de datos y a la memoria del proceso, así que una contraseña adicional no supone ningún obstáculo.

Por eso, el primer intento debería ser siempre este:

sudo mariadb
sudo mysql

Ten en cuenta que sudo mysql -u root -p no funciona, porque el -p conmuta a autenticación por contraseña. Ahí es justo donde falla la mayoría. Sin -p y con sudo sueles aterrizar directamente en el prompt. Desde ahí defines la contraseña nueva en dos segundos, sin tocar siquiera la base de datos.

La segunda vía de rescate es la cuenta de mantenimiento de la distribución. En Ubuntu con el paquete mysql-server sigue existiendo el archivo /etc/mysql/debian.cnf, que contiene las credenciales de una cuenta con todos los privilegios y que solo root puede leer:

sudo ls -l /etc/mysql/debian.cnf
sudo mysql --defaults-file=/etc/mysql/debian.cnf -e "SELECT current_user();"

Si te devuelve una línea, ya estás dentro y puedes seguir trabajando de inmediato. Eso sí, no esperes root@localhost: la consulta responde con debian-sys-maint@localhost. Es lo correcto, porque esa cuenta de mantenimiento tiene ALL PRIVILEGES y basta de sobra para el restablecimiento, aunque con ella no eres root. Además, esta vía es exclusiva de Debian y Ubuntu. En AlmaLinux, Rocky Linux y Oracle Linux no existe ni el directorio /etc/mysql/ ni la cuenta, y ahí lo que sirve es el inicio de sesión por socket como root del apartado anterior. En MariaDB, a partir de la versión 10.4 esta cuenta ya no se crea de nuevo (allí el archivo suele limitarse a apuntar a root a través del socket), pero en instalaciones existentes sigue estando presente muy a menudo. Echar un vistazo no cuesta nada y, si sale bien, te ahorra todo el resto de esta guía.

¿Qué base de datos se está ejecutando aquí en realidad?

No es una formalidad, sino algo que determina cada uno de los comandos que vienen después. En Debian hace años que no hay ningún paquete mysql-server en el archivo oficial, así que ahí corre prácticamente siempre MariaDB, aunque exista el comando mysql. Ese comando no es más que un enlace simbólico al cliente de MariaDB. Ahora mismo, en las distribuciones encuentras esto:

Sistemamysql-servermariadb-server
Debian 13no disponible11.8
Debian 12no disponible10.11
Ubuntu 24.048.010.11
Ubuntu 22.048.010.6

Pregúntale al servidor mismo, no al cliente:

systemctl list-units --type=service --all | grep -Ei 'mysql|mariadb'
mysqladmin --version
mariadbd --version

El --all forma parte del comando, porque de lo contrario list-units solo muestra las units cargadas y activas. Justo en el caso en el que necesitas el comando, es decir, con un servicio que no está en marcha, la salida quedaría vacía. mysqladmin --version existe en ambos bandos y nombra el motor sin rodeos: los sistemas con MariaDB responden con ... Distrib 11.8.6-MariaDB .... En mariadbd --version, un command not found en un sistema puramente MySQL es el resultado esperado y no un fallo; a la inversa vale lo mismo para los comandos propios de mysqld en un sistema puramente MariaDB.

Si la unit se llama mariadb.service, estás trabajando con MariaDB. Si se llama mysql.service, con MySQL. En los sistemas con MariaDB existe además un alias mysql.service que apunta a mariadb.service, por eso la salida de systemctl list-units dice más que la simple existencia de un nombre.

Los nombres de las units difieren entre familias de distribuciones, y todas las llamadas a systemctl de esta guía están escritas para Debian y Ubuntu. En la familia Red Hat no existe ninguna unit llamada mysql.service: ahí systemctl status mysql responde con Unit mysql.service could not be found. En ese caso usa siempre los nombres de la columna derecha, también en la ruta del directorio de drop-in:

QuéDebian y UbuntuAlmaLinux, Rocky, RHEL
Unit de MariaDBmariadb.servicemariadb.service
Unit de MySQLmysql.servicemysqld.service
Directorio drop-in de MySQL/etc/systemd/system/mysql.service.d//etc/systemd/system/mysqld.service.d/
Binario del servidor MySQL/usr/sbin/mysqld/usr/libexec/mysqld --basedir=/usr
Configuración/etc/mysql//etc/my.cnf y /etc/my.cnf.d/

Aislar el servidor antes: por qué este paso no es opcional

Con --skip-grant-tables, el servidor no carga las tablas de privilegios. Eso no significa "root puede entrar sin contraseña", sino "cualquiera puede hacer cualquier cosa, sin contraseña y como el usuario que quiera". En ese estado no hay autenticación ni comprobación de privilegios, tampoco para las bases de datos de tus clientes.

En ese caso, MySQL 8 activa automáticamente skip_networking, es decir, deja de aceptar conexiones TCP. Aun así, no te fíes de eso y añade siempre la opción por tu cuenta. En MariaDB es de todos modos la recomendación documentada, y quien administra los dos sistemas prefiere no tener que acordarse de cuál de ellos piensa por él.

--skip-grant-tables --skip-networking

Hay dos puntos que se pasan por alto con frecuencia. Primero: skip_networking solo cierra el puerto de red. El socket Unix en /run/mysqld/mysqld.sock sigue abierto y, en muchos sistemas, está al alcance de todos los usuarios locales. Un proceso PHP comprometido bajo www-data puede leer en esa ventana cualquier base de datos del servidor. Por eso, mantén la ventana lo más corta posible y no ejecutes la operación mientras haya un servidor web con código desconocido en marcha. Segundo: para antes todo lo que se conecte de forma automática, es decir, el servidor web y los servicios de aplicación. Sus intentos de conexión no solo molestan, sino que en este estado se ejecutan con todos los privilegios.

Si el servidor es accesible desde fuera, cierra además el firewall. Cómo montarlo de forma limpia y permanente lo tienes en configurar el firewall UFW.

sudo apt-get install -y ufw
sudo ufw deny 3306/tcp
sudo ss -ltnp | grep 3306

La primera línea no sobra: en una instalación mínima de Debian, ufw no viene preinstalado y el comando termina con sudo: ufw: command not found. En AlmaLinux, Rocky Linux y RHEL, ufw ni siquiera existe: allí el filtrado de paquetes va por firewalld:

sudo firewall-cmd --permanent --remove-service=mysql
sudo firewall-cmd --reload

En todas las instalaciones comprobadas de Debian y Ubuntu, bind-address ya está en 127.0.0.1, confirmado con ss -ltnp. En ese caso el servidor no acepta de todos modos ninguna conexión desde fuera, y la regla del firewall es la segunda barrera, no la protección propiamente dicha.

MariaDB: restablecer la contraseña

La unit de MariaDB arranca el servidor con ExecStart=/usr/sbin/mariadbd $MYSQLD_OPTS. Esa variable está prevista justo para casos así, de modo que no tienes que editar ningún archivo. Compruébalo un momento y sabrás que el camino siguiente funciona en tu sistema:

systemctl cat mariadb | grep ExecStart

Después, en este orden:

sudo systemctl stop mariadb
sudo systemctl set-environment MYSQLD_OPTS="--skip-grant-tables --skip-networking"
sudo systemctl start mariadb
sudo mariadb -u root

En el prompt, lo primero es FLUSH PRIVILEGES. Sin ese paso el servidor todavía no tiene las tablas de privilegios en memoria y rechaza cualquier gestión de cuentas. Después ya defines la contraseña:

FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket OR mysql_native_password USING PASSWORD('TuNuevaContraseña');

Esta sintaxis algo aparatosa es intencionada y constituye el punto específico de MariaDB más importante de toda la guía. Desde la versión 10.4, MariaDB puede mantener varios métodos de autenticación por cuenta, y así es exactamente como queda configurado root tras una instalación por paquete: primero el socket y, como alternativa, la contraseña. Si en su lugar usas el simple ALTER USER 'root'@'localhost' IDENTIFIED BY '...', sustituyes toda la cadena por autenticación exclusivamente por contraseña. Funciona, pero a partir de ahí sudo mariadb ya no entra sin contraseña, y los scripts internos de mantenimiento de la distribución que dependen del socket se quedan sin nada. Con eso solo habrás aplazado el problema un año.

Para terminar, deshaz el estado excepcional:

sudo systemctl stop mariadb
sudo systemctl unset-environment MYSQLD_OPTS
sudo systemctl start mariadb

No te olvides de unset-environment. La variable cuelga del gestor de systemd, no del servicio, y sobrevive a cualquier reinicio del servicio. Si por la noche una actualización de paquetes reinicia MariaDB, a partir de ese momento tu base de datos sigue funcionando sin ninguna comprobación de privilegios y nadie se entera. Solo un reinicio completo del servidor elimina la variable por sí solo.

MySQL 8: aquí el comando de la mayoría de las guías no hace nada

Para MySQL circula la misma receta con systemctl set-environment MYSQLD_OPTS=.... Viene de la documentación de Oracle y encaja con los paquetes del propio Oracle. Pero la unit del archivo de Ubuntu tiene otra forma: ahí pone simplemente ExecStart=/usr/sbin/mysqld, sin variable. El comando se ejecuta, no informa de ningún error y aun así el servidor arranca con toda normalidad y con la comprobación de privilegios activa. Te quedas entonces delante de un Access denied sin entender nada. Compruébalo tú mismo:

systemctl cat mysql | grep ExecStart

Si ahí no aparece ningún $MYSQLD_OPTS, necesitas un drop-in. Y ya que vas a crear uno, escoge directamente la vía mejor: --init-file. Con ella el servidor arranca con toda normalidad con la comprobación de privilegios y ejecuta al iniciarse un archivo SQL con todos los permisos. No queda ninguna ventana abierta por la que alguien pueda entrar sin contraseña. Oracle recomienda esta variante de forma explícita frente a --skip-grant-tables.

sudo systemctl stop mysql
printf "ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'TuNuevaContraseña';\n" | sudo tee /var/lib/mysql-files/kh-reset.sql
sudo chown mysql:mysql /var/lib/mysql-files/kh-reset.sql
sudo chmod 600 /var/lib/mysql-files/kh-reset.sql
sudo mkdir -p /etc/systemd/system/mysql.service.d

El IDENTIFIED WITH caching_sha2_password es la parte decisiva y la razón por la que incontables guías fracasan en este punto sin mostrar ningún error. En Debian y Ubuntu, root@localhost usa el plugin auth_socket también con MySQL. Un simple IDENTIFIED BY 'contraseña' sí define el hash de la contraseña, pero no cambia el plugin. Después, en mysql.user sigue apareciendo auth_socket, el servicio arranca sin problemas, no sale ni un solo mensaje de error y, aun así, cada inicio de sesión con contraseña termina con ERROR 1698 (28000): Access denied for user 'root'@'localhost'. Especialmente traicionero: quien hace la contraprueba como usuario root del sistema pasa sin contraseña gracias a auth_socket y da el restablecimiento por bueno. Por eso, prueba desde otra cuenta o por TCP. Solo con clientes muy antiguos que no manejan caching_sha2_password conviene usar mysql_native_password en su lugar, con las limitaciones del párrafo de más abajo.

El directorio /var/lib/mysql-files está elegido a propósito: pertenece al usuario de la base de datos y está autorizado en el perfil de AppArmor de mysqld. Si dejas el archivo en /root o /tmp, el arranque puede fallar por culpa de AppArmor y el mensaje del log resulta poco útil. Ahora, el drop-in:

[Service]
ExecStart=
ExecStart=/usr/sbin/mysqld --init-file=/var/lib/mysql-files/kh-reset.sql

La primera línea ExecStart vacía es obligatoria; de lo contrario systemd añade tu comando al que ya existe y rechaza el servicio con un error de configuración. Guárdalo en /etc/systemd/system/mysql.service.d/override.conf y después:

sudo systemctl daemon-reload
sudo systemctl start mysql
sudo mysql -u root -p

Si el inicio de sesión funciona, retira las dos cosas, el archivo SQL y el drop-in:

sudo rm -f /var/lib/mysql-files/kh-reset.sql
sudo rm -f /etc/systemd/system/mysql.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart mysql

Si aun así prefieres la vía clásica, sustituye en el drop-in la línea por ExecStart=/usr/sbin/mysqld --skip-grant-tables --skip-networking, conéctate con sudo mysql y ejecuta allí primero FLUSH PRIVILEGES; y después ALTER USER. Un apunte sobre el cifrado: MySQL 8 usa caching_sha2_password de forma predeterminada. Si después una aplicación muy antigua se queja con "The server requested authentication method unknown to the client", ayuda IDENTIFIED WITH mysql_native_password BY '...'. Pero es un callejón sin salida, porque ese método está considerado obsoleto desde la 8.0.34 y ya no se incluye en MySQL 8.4. Es mejor actualizar el cliente.

Los mensajes de error, palabra por palabra

ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement. Te has olvidado de FLUSH PRIVILEGES;. Ejecútalo y entonces ALTER USER funciona.

ERROR 1288 (HY000): The target table user of the UPDATE is not updatable. Estás siguiendo una guía antigua que propone UPDATE mysql.user SET password=.... A partir de MariaDB 10.4 los privilegios viven en mysql.global_priv, y mysql.user es ya solo una vista sobre esa tabla. Usa ALTER USER o SET PASSWORD. Por cierto, escribir directamente en las tablas de privilegios ya era antes un buen método para destrozar la cuenta de forma definitiva.

ERROR 1698 (28000): Access denied for user 'root'@'localhost'. No es una contraseña equivocada, sino justo lo contrario: la cuenta espera autenticación por socket y tú no vas como usuario root del sistema o has pasado -p. Inténtalo de nuevo con sudo y sin -p.

ERROR 1524 (HY000): Plugin 'unix_socket' is not loaded. La cuenta apunta a un plugin que el servidor en ejecución no conoce, algo típico tras un cambio de MariaDB a MySQL o tras copiar un directorio de datos. Reconfigura la cuenta con el procedimiento de arriba para que use un método adecuado.

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/run/mysqld/mysqld.sock' (2). El servidor no está en marcha. Mira primero systemctl status y el log, no sigas probando desde el cliente.

mysqld: Can't create directory '/run/mysqld/' (Errcode: 13 - Permission denied) o bien un arranque que se interrumpe de inmediato. Esto ocurre cuando el servidor se ha lanzado a mano en lugar de a través de systemd, porque entonces falta el directorio de tiempo de ejecución. Reparación:

sudo mkdir -p /run/mysqld
sudo chown mysql:mysql /run/mysqld

Job for mysql.service failed because the control process exited with error code. Este mensaje, por sí solo, no dice nada. La causa real está en el journal y en el log de errores:

sudo journalctl -u 'mysql*' -u 'mariadb*' -n 60 --no-pager

El patrón con los dos nombres de unit está elegido a propósito, porque la consulta individual más obvia lleva a una trampa silenciosa. En Debian con MariaDB, mysql.service es solo un alias de mariadb.service. systemctl resuelve el alias, pero el journal indexa las entradas bajo el nombre real de la unit, así que journalctl -u mysql responde con -- No entries -- y código de salida 0 aunque el journal esté lleno. A la inversa, journalctl -u mariadb devuelve igualmente -- No entries -- en un sistema Ubuntu con MySQL.

Con el archivo de errores ocurre algo parecido. El /var/log/mysql/error.log que se cita en todas partes solo existe en Ubuntu con MySQL. En Debian con MariaDB, el directorio /var/log/mysql/ ni siquiera existe, porque log_error está comentado en 50-server.cnf y MariaDB escribe en el journal. La línea que corresponde según el sistema:

Sistema y servidorComando
Debian o Ubuntu, MariaDBsudo journalctl -u mariadb -n 60 --no-pager
Ubuntu, MySQLsudo tail -n 60 /var/log/mysql/error.log
AlmaLinux, Rocky, RHEL, MySQLsudo tail -n 60 /var/log/mysql/mysqld.log
AlmaLinux, Rocky, RHEL, MariaDBsudo tail -n 60 /var/log/mariadb/mariadb.log

Si no quieres adivinar la ruta, pregunta al propio servidor: sudo mariadb -e "SHOW VARIABLES LIKE 'log_error';" o lo mismo con mysql.

Las tres causas más frecuentes en este punto: una errata en el drop-in (entonces systemd señala la línea), un disco lleno (sobre eso, disco lleno en Linux) o un segundo proceso del servidor que sigue vivo y mantiene bloqueados los archivos de datos. Esto último lo compruebas con pgrep -a mariadbd o pgrep -a mysqld antes de volver a arrancar.

Si después del restablecimiento tú entras pero tus aplicaciones siguen recibiendo un rechazo, el problema está en otro sitio: aplicaciones como WordPress o Nextcloud usan sus propios usuarios de base de datos, no root. Los detalles, en resolver Access denied for user en MySQL.

Cómo saber que de verdad ha funcionado

Un inicio de sesión correcto no basta como prueba, porque en el estado de emergencia también funciona sin ninguna contraseña. Por eso, comprueba cuatro cosas una vez que el servicio vuelve a funcionar con normalidad.

Primero: ya no queda ninguna configuración especial. La primera salida tiene que estar vacía, y la segunda no debe mostrar ninguna opción adicional.

systemctl show-environment | grep MYSQLD_OPTS
systemctl cat mariadb | grep ExecStart

Segundo: la comprobación de privilegios vuelve a estar activa. Un inicio de sesión con una contraseña deliberadamente equivocada tiene que fallar. Si pasa, el servidor sigue funcionando abierto.

Tercero: la contraseña nueva y el método esperado constan en la cuenta. En MariaDB lo consultas así, y en MySQL sin la columna JSON:

sudo mariadb -e "SELECT user, host, plugin FROM mysql.user WHERE user='root';"
sudo mysql -e "SELECT user, host, plugin FROM mysql.user WHERE user='root';"

Cuarto: el puerto de red se comporta otra vez como antes. Un servidor de base de datos que solo se usa en local debería volver a escuchar exclusivamente en 127.0.0.1 después de la limpieza:

sudo ss -ltnp | grep 3306
grep -rs bind-address /etc/mysql/ /etc/my.cnf /etc/my.cnf.d/

El -s y las tres rutas son intencionados. grep -r bind-address /etc/mysql/ por sí solo aborta en la familia Red Hat con No such file or directory, porque allí no hay ningún /etc/mysql/. Con -s, grep pasa por alto en silencio las rutas que no existen, y la línea sirve para los dos mundos.

Limpiar para que no vuelva a ocurrir

Puede que ahora la contraseña esté en sitios en los que no piensas. Un comando con -e "ALTER USER ... IDENTIFIED BY '...'" acaba en ~/.bash_history, y un comando escrito en el prompt acaba en el archivo de historial del cliente de base de datos. Hay que limpiar las dos cosas:

history -c
rm -f ~/.mysql_history ~/.mariadb_history

Los dos nombres de archivo son necesarios porque el cliente ha cambiado de nombre. Hasta MariaDB 10.11, es decir, hasta Debian 12 incluido, escribe en ~/.mysql_history. A partir de MariaDB 11, o sea, desde Debian 13, escribe en ~/.mariadb_history. Quien borra ahí solo el archivo antiguo deja la contraseña, escrita en texto plano, sobre el disco sin darse cuenta. Todavía mejor es impedir que el historial llegue a crearse: export MYSQL_HISTFILE=/dev/null o export MARIADB_HISTFILE=/dev/null antes de la sesión, o directamente la vía por --init-file del apartado de MySQL, en la que la contraseña nunca pasa por una sesión interactiva.

Más sensato que una contraseña que dentro de un año volverás a olvidar es un montaje que en el día a día no necesite contraseña. En Debian y Ubuntu eso significa que root se queda con unix_socket o auth_socket, y que para todo lo demás creas usuarios normales con exactamente los privilegios que necesita cada aplicación. Si te hace falta el acceso desde otro equipo, tunelízalo por SSH en lugar de abrir el puerto 3306, ver conectarse al servidor por SSH.

Ya que estás trabajando con la base de datos, aprovecha para el resto: eliminar usuarios anónimos, borrar la base de datos de prueba y desactivar el acceso remoto para root. De eso se encarga mariadb-secure-installation o mysql_secure_installation en pocos minutos, descrito en detalle en asegurar MariaDB y MySQL. Y como la contraseña rara vez es lo único que está mal en un servidor recién heredado, merece la pena repasar la lista de comprobación para servidores root nuevos.

Una última idea sobre el orden: antes de dejar un servidor de producción en el estado sin privilegios, haz un backup del directorio de datos o un snapshot. El restablecimiento en sí es inofensivo, pero un servicio que ya no arranca por culpa de una errata en la unit deja de serlo a las tres de la madrugada.

Preguntas frecuentes

He olvidado la contraseña de root. ¿Tengo que parar MySQL de verdad?
La mayoría de las veces no. En Debian y Ubuntu, el root de la base de datos está protegido por el socket Unix, no por una contraseña. Prueba primero sudo mariadb o sudo mysql, en ambos casos sin la opción -p. Si funciona, defines la contraseña nueva en caliente con ALTER USER. Solo cuando esa vía falla con Access denied necesitas el reinicio con la comprobación de privilegios desactivada.
¿Por qué recibo ERROR 1290 aunque he arrancado con skip-grant-tables?
Porque en ese estado el servidor no ha cargado las tablas de privilegios y por eso no puede ejecutar ninguna gestión de cuentas. Ejecuta primero FLUSH PRIVILEGES en el prompt y después ALTER USER funciona como siempre. El mensaje completo dice: The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement.
¿Mi servidor es vulnerable mientras dura el restablecimiento?
Sí, y por completo. Con la comprobación de privilegios desactivada ya no hay autenticación: cualquier intento de conexión tiene todos los permisos sobre todas las bases de datos. MySQL 8 apaga de paso el puerto de red de forma automática, MariaDB no necesariamente. Por eso añade siempre --skip-networking por tu cuenta, para el servidor web y los servicios de aplicación, y limita la ventana a unos pocos minutos. El socket local sigue abierto de todas formas para todos los usuarios del sistema.
¿Cuál es la diferencia entre MySQL 8 y MariaDB al restablecer la contraseña?
Tres cosas. Primero, la unit de systemd: en MariaDB sirve systemctl set-environment MYSQLD_OPTS, en el MySQL del archivo de Ubuntu no, y ahí necesitas un drop-in con su propia línea ExecStart. Segundo, las tablas de privilegios: desde MariaDB 10.4, mysql.user es solo una vista sobre mysql.global_priv y los UPDATE directos fallan con ERROR 1288. Tercero, la sintaxis de cuenta: MariaDB puede mantener los dos métodos a la vez con IDENTIFIED VIA unix_socket OR mysql_native_password, mientras que MySQL solo conoce un método por cuenta. En MySQL lo decisivo es el WITH: ALTER USER ... IDENTIFIED BY define únicamente el hash de la contraseña y deja el plugin en auth_socket, con lo que el inicio de sesión con contraseña sigue fallando con ERROR 1698. Lo correcto es ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '...'.
Después del restablecimiento entro como root, pero mi web sigue diciendo Access denied. ¿Por qué?
Porque aplicaciones como WordPress, Nextcloud o las tiendas online no trabajan con la cuenta de root, sino con sus propios usuarios de base de datos. Sus contraseñas están en el archivo de configuración de cada aplicación y el restablecimiento de root no las toca. Revisa el usuario configurado en la aplicación y, si hace falta, ajusta su contraseña.
¿Qué pasa si me olvido de systemctl unset-environment?
La variable cuelga del gestor de systemd y sobrevive a cualquier reinicio del servicio. Si por la noche una actualización de paquetes reinicia la base de datos, a partir de ese momento seguirá funcionando de forma permanente sin comprobación de privilegios, y sin que nadie lo note. Solo un reinicio completo del servidor la elimina por sí solo. Cuando termines, comprueba con systemctl show-environment que MYSQLD_OPTS ya no está definida.

MySQL MariaDB Contraseña de root Debian Ubuntu systemd Base de datos Administración de servidores unix_socket Resolución de problemas