Aller au contenu

MySQL : utilisateurs et droits

Un compte MySQL est identifié par un nom d’utilisateur ET un hôte ('app'@'localhost'). Les exemples créent un compte pour l’application qui utilise la base boutique.

CREATE USER 'app'@'localhost' IDENTIFIED BY 'mot_de_passe_solide';
CREATE USER 'app'@'192.168.1.%' IDENTIFIED BY 'mot_de_passe_solide'; -- depuis un réseau précis
CREATE USER 'lecture'@'localhost' IDENTIFIED BY 'autre_mot_de_passe';
Hôte Signification
localhost Connexion depuis la machine locale (socket)
127.0.0.1 Connexion locale par TCP
192.168.1.% Toute adresse du réseau (% = joker)
% N’importe quelle machine (à éviter)
GRANT SELECT, INSERT, UPDATE, DELETE ON boutique.* TO 'app'@'localhost';
GRANT SELECT ON boutique.* TO 'lecture'@'localhost';
CREATE USER 'migrations'@'localhost' IDENTIFIED BY 'mot_de_passe_migrations';
GRANT ALL PRIVILEGES ON boutique.* TO 'migrations'@'localhost'; -- tous les droits sur une base

Appliquer le principe du moindre privilège : l’application n’a besoin que de SELECT, INSERT, UPDATE, DELETE sur sa base, pas de DROP ni de droits globaux. Un compte distinct, plus privilégié, sert aux migrations de schéma.

Portées possibles : *.* (tout le serveur), boutique.* (une base), boutique.clients (une table), boutique.clients (nom, email) (des colonnes).

SHOW GRANTS FOR 'app'@'localhost';
SHOW GRANTS; -- pour le compte courant
SELECT user, host, plugin FROM mysql.user; -- comptes et plugin d'authentification
REVOKE DELETE ON boutique.* FROM 'app'@'localhost';
ALTER USER 'app'@'localhost' IDENTIFIED BY 'nouveau_mot_de_passe';
ALTER USER 'app'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;
RENAME USER 'app'@'localhost' TO 'appli'@'localhost';
DROP USER IF EXISTS 'temporaire'@'localhost';

Les droits accordés avec GRANT s’appliquent sans FLUSH PRIVILEGES. Cette commande n’est utile qu’après une modification directe des tables mysql.*, déconseillée.

Un rôle regroupe des droits attribués à plusieurs comptes :

CREATE ROLE 'lecteur_boutique';
GRANT SELECT ON boutique.* TO 'lecteur_boutique';
GRANT 'lecteur_boutique' TO 'lecture'@'localhost';
SET DEFAULT ROLE 'lecteur_boutique' TO 'lecture'@'localhost';
SHOW GRANTS FOR 'lecture'@'localhost' USING 'lecteur_boutique';

Le plugin par défaut est caching_sha2_password. Pour un compte qui se connecte seulement par le compte système (comme root) :

CREATE USER 'sauvegarde'@'localhost' IDENTIFIED WITH auth_socket;

Le nom d’utilisateur MySQL doit alors correspondre au compte système.

INSTALL COMPONENT 'file://component_validate_password';
SHOW VARIABLES LIKE 'validate_password%';
SET GLOBAL validate_password.length = 12;

Les mots de passe trop faibles sont ensuite refusés à la création et à la modification des comptes (erreur 1819). Avec la politique MEDIUM par défaut, un mot de passe doit contenir au moins 8 caractères avec majuscules, minuscules, chiffres et caractères spéciaux : les exemples de cette page, volontairement simples, sont à remplacer par des mots de passe conformes.

Par défaut, MySQL n’écoute que sur 127.0.0.1. Pour l’ouvrir au réseau :

  1. Modifier /etc/mysql/mysql.conf.d/mysqld.cnf :

    bind-address = 192.168.1.10
  2. Créer un compte limité à l’adresse du client ('app'@'192.168.1.20').

  3. Redémarrer : sudo systemctl restart mysql.

  4. Ouvrir le port uniquement pour le client :

    Fenêtre de terminal
    sudo ufw allow from 192.168.1.20 to any port 3306 proto tcp
Symptôme Piste
ERROR 1045 Access denied Mauvais mot de passe, ou le compte existe pour un autre hôte (SELECT user, host FROM mysql.user;)
ERROR 1396 Operation CREATE USER failed Le compte existe déjà : DROP USER ou ALTER USER
ERROR 1819 does not satisfy the current policy Mot de passe refusé par la politique : en choisir un plus long et plus varié
Client ancien refusé (MySQL 8.4) Plugin mysql_native_password désactivé : voir Installation