Table des matières :
- Qualifier le symptôme : #1045 MySQL vs « CSRF token mismatch »
- Erreur MySQL #1045 dans phpMyAdmin : matrice des causes et tests rapides
- Corriger #1045 proprement : utilisateurs, plugins, hôtes et privilèges
- Problèmes CSRF phpMyAdmin : comprendre tokens, cookies et sessions (et ce qui les casse)
- Corrections CSRF : checklist serveur (PHP), proxy (Nginx/Apache) et configuration phpMyAdmin
- Fiabiliser l’accès à phpMyAdmin en production : surface d’attaque, journalisation, alternatives
La combinaison « phpMyAdmin + MySQL » est assez impitoyable : l’erreur #1045 (Access denied) est purement côté serveur SQL, alors que les problèmes CSRF sont presque toujours côté HTTP/session/cookies (et souvent aggravés par un proxy/CDN). Mélanger les deux fait perdre du temps ; il faut instrumenter, isoler, puis corriger sans casser la sécurité.
Contexte et périmètre de ce guide (important pour éviter les faux diagnostics) : exemples validés sur phpMyAdmin 5.2.x (très répandu en mutualisé et Plesk/cPanel), MySQL 5.7/8.0 et MariaDB 10.6+, avec PHP 8.1+ (FPM/Apache). Les commandes sont identiques sous Debian/Ubuntu/RHEL, seules les unités systemd et les chemins varient.
Une règle simple pour gagner du temps en incident :
- si l’échec apparaît avant la sélection de base (erreur SQL d’auth) → piste MySQL/MariaDB ;
- si l’interface s’ouvre mais les actions POST (connexion, import, suppression, export) échouent avec un message de jeton → piste sessions/cookies/cache.
Qualifier le symptôme : #1045 MySQL vs « CSRF token mismatch »
L’erreur MySQL #1045 est un refus d’authentification au niveau du serveur MySQL/MariaDB. Le message canonique, tel qu’affiché par le client mysql, est explicite : ERROR 1045 (28000): Access denied for user 'user'@'host' (using password: YES). Si vous voyez cette chaîne (ou une variante) dans phpMyAdmin, la résolution se fait dans MySQL/MariaDB (utilisateur, host, plugin d’auth, privilèges, mot de passe, réseau), pas dans PHP.
À l’inverse, les erreurs CSRF dans phpMyAdmin ressemblent à : « Token mismatch », « CSRF token is invalid », « Le jeton CSRF est invalide ». Techniquement, c’est un problème de session PHP et de cookies (valeur qui ne revient pas, session perdue, cookie non stocké, cache intermédiaire, horloge incohérente). MySQL peut être parfaitement sain ; vous êtes simplement incapable de maintenir un état authentifié côté phpMyAdmin.
Pour éviter les faux diagnostics, utilisez une mini-matrice de tri (utile quand plusieurs équipes se renvoient la balle) :
| Ce que vous observez | Indice principal | Couche à investiguer en premier |
|---|---|---|
Message ERROR 1045 (28000) / “Access denied” |
l’utilisateur et l’hôte sont mentionnés ('user'@'host') |
MySQL/MariaDB (comptes, host, plugin, droits) |
| “Token mismatch” après login ou lors d’une action | souvent aléatoire, dépend du navigateur ou du réseau | HTTP + PHP session (cookies, proxy, cache, LB) |
| phpMyAdmin fonctionne en local mais pas via domaine | changement de schéma (HTTP/HTTPS) ou de proxy | reverse proxy / headers / cookies |
CLI mysql OK mais phpMyAdmin KO |
divergence de cible (TCP vs socket) ou config phpMyAdmin | phpMyAdmin + PHP (host, connect_type, restrictions) |
Avant toute modification, capturez des preuves. Côté navigateur : onglet Network → vérifiez que la réponse de /phpmyadmin/ (ou équivalent) n’est pas mise en cache, et inspectez les en-têtes Set-Cookie (Domain/Path/SameSite/Secure). Vérifiez aussi les codes HTTP : un 301/302 en chaîne (HTTP→HTTPS) ou un 403 WAF au mauvais moment peut casser le flux de session.
Côté serveur : récupérez les logs PHP-FPM/Apache/Nginx et, si possible, les logs MySQL. Sur Debian/Ubuntu, les emplacements courants (à adapter) ressemblent à :
- PHP-FPM :
/var/log/php8.x-fpm.loget/ou logs pool (/var/log/php-fpm/*.log) - Nginx :
/var/log/nginx/access.log+error.log - Apache :
/var/log/apache2/access.log+error.log - MySQL/MariaDB :
/var/log/mysql/error.logou/var/log/mariadb/mariadb.log
Pour le volet logs MySQL, la méthodologie de base (general log / slow log) est la même que celle détaillée dans cet article : Logs Amazon Lightsail : activer general log et slow query MySQL.
Erreur MySQL #1045 dans phpMyAdmin : matrice des causes et tests rapides
La première erreur fréquente (et la plus bête) : phpMyAdmin n’utilise pas les bons identifiants. En mutualisé, vous avez parfois plusieurs bases et plusieurs users. Sur un serveur e-commerce, vous réutilisez souvent les identifiants applicatifs (ex. PrestaShop). Pour mémoire :
- PrestaShop 1.6 :
config/settings.inc.php - PrestaShop 1.7/8/9 :
app/config/parameters.php(le cœur a encore cette convention dans la majorité des installations)
Ne copiez pas à la main « de tête ». Lisez le fichier, et testez les identifiants avec le client MySQL depuis la même machine que phpMyAdmin (ça élimine les hypothèses réseau). Deux tests utiles : socket vs TCP (car localhost peut basculer sur socket et matcher un autre user@host).
# Test TCP explicite (évite le "localhost" implicite)
mysql --protocol=TCP -h 127.0.0.1 -P 3306 -u USER -p
# Test en visant localhost (peut utiliser un socket selon la config client)
mysql -h localhost -u USER -p
Si la connexion réussit en CLI mais échoue dans phpMyAdmin, vous êtes plutôt sur un problème de configuration phpMyAdmin (auth type, host/socket, restrictions) ou de différence de cible (phpMyAdmin pointe vers un autre serveur). Si la connexion échoue en CLI avec le même #1045, votre cause est bien côté MySQL.
Deuxième cause fréquente sur MySQL 8 : mismatch de plugin d’authentification. MySQL 8 utilise caching_sha2_password par défaut, alors que certains clients/versions de PHP (ou des stacks vieillissantes) s’attendent à mysql_native_password. phpMyAdmin, via PHP mysqli/PDO, dépend de la version de libmysqlnd ; dans des environnements legacy, l’auth peut échouer de façon contre-intuitive et remonter en #1045. Dans mysql.user, regardez plugin.
Troisième cause : la composante user@host. En MySQL, user et host forment la clé d’authentification, et user@localhost n’est pas user@%. phpMyAdmin peut se connecter via TCP (127.0.0.1) ou socket (localhost) selon configuration. Ce simple détail change la ligne matchée dans mysql.user et déclenche un #1045 alors que « le même user » fonctionne ailleurs.
Quatrième cause, très “terrain” après une migration : l’utilisateur existe, le mot de passe est bon, mais l’hôte a changé. Exemple typique : base sur un serveur dédié/VM séparée, et après bascule (nouvelle VM, nouveau conteneur, nouveau NAT), l’IP source vue par MySQL n’est plus celle autorisée. Dans les hébergements où l’on durcit user@host, ça se traduit immédiatement par #1045.
Enfin, ne négligez pas le cas où l’erreur #1045 affichée dans phpMyAdmin concerne… un compte technique (ex. controluser utilisé pour le “configuration storage” de phpMyAdmin). Dans ce scénario, la connexion “utilisateur” peut marcher, mais phpMyAdmin affiche des avertissements et certaines fonctionnalités se dégradent. La différence se voit dans le texte exact de l’erreur : l’utilisateur mentionné n’est pas celui que vous saisissez au login.
Corriger #1045 proprement : utilisateurs, plugins, hôtes et privilèges
Évitez les “solutions” de type GRANT ALL ON *.* TO ... en panique. Une console root/MySQL-admin, un backup, et vous corrigez de manière déterministe. Le principe est simple : identifier la ligne réellement utilisée (user, host, plugin), corriger mot de passe + host, puis appliquer des privilèges minimaux.
Connectez-vous en admin MySQL (root) depuis la machine SQL :
SELECT user, host, plugin FROM mysql.user WHERE user = 'USER';
SHOW GRANTS FOR 'USER'@'HOST';
Astuce de diagnostic : si vous ne savez pas quel host matche réellement, listez les entrées existantes (et repérez les doublons localhost/127.0.0.1/%) :
SELECT user, host, plugin
FROM mysql.user
WHERE user = 'USER'
ORDER BY host;
Si vous constatez que vous n’avez que USER@localhost mais que phpMyAdmin arrive via 127.0.0.1 (donc host = 127.0.0.1), créez explicitement l’entrée correspondante (ou harmonisez la config phpMyAdmin pour forcer socket). Exemple minimaliste (adapté à une base PrestaShop) :
CREATE USER 'ps_app'@'127.0.0.1' IDENTIFIED BY 'mot_de_passe_fort';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER
ON prestashop_db.* TO 'ps_app'@'127.0.0.1';
FLUSH PRIVILEGES;
Deux points importants en prod :
- Préférez créer un nouvel utilisateur (ou au minimum réinitialiser explicitement) plutôt que “réparer à l’aveugle”. Ça vous donne un état connu, reproductible et auditable. Une fois validé, vous basculez l’application (et/ou phpMyAdmin) sur ce compte.
- Évitez
host='%'sauf contrainte forte. Sur une boutique e-commerce, c’est rarement nécessaire : un[email protected]ouuser@IP_DU_WEBSERVERréduit drastiquement la surface d’attaque.
Sur la question du plugin d’authentification, soyez pragmatiques : si vous êtes en MySQL 8 et que votre stack PHP est moderne (PHP 8.2+ correctement packagé), gardez caching_sha2_password. Si vous êtes coincé sur une lib cliente incompatible, l’ajustement est possible au niveau user :
ALTER USER 'ps_app'@'127.0.0.1'
IDENTIFIED WITH mysql_native_password BY 'mot_de_passe_fort';
FLUSH PRIVILEGES;
Ce contournement doit être documenté et temporaire : l’objectif, à moyen terme, est de mettre à jour la chaîne PHP/libmysqlnd, pas de figer un plugin plus ancien. Pour une démarche plus globale de durcissement (TLS, pare-feu, audit des privilèges), référez-vous à : Sécurité MySQL : pare-feu, TLS, privilèges minimaux et audit.
Enfin, si vous êtes en environnement hébergé (DB distante), le #1045 masque parfois un problème de résolution DNS / IP source : le serveur MySQL reçoit la connexion depuis une IP inattendue (NAT, proxy, container bridge), donc aucun user@host ne matche. Dans ce cas : (1) loggez l’IP source côté MySQL (general log temporaire), (2) créez un user@'x.x.x.x' spécifique ou adaptez le host (note : MySQL n’accepte pas le CIDR dans le champ host — '10.%' est un motif, pas du CIDR), (3) préférez un tunnel (SSH) plutôt que d’ouvrir le port 3306.
Mini-scénario réaliste : vous migrez d’un serveur web vers un nouveau (changement d’IP), mais vous gardez le même serveur SQL. L’application (ou phpMyAdmin) tente de se connecter avec user@NEW_IP, alors que le compte n’existe que pour user@OLD_IP. Résultat : #1045 immédiat, alors que “le mot de passe n’a pas changé”. Dans ce contexte, la correction n’est pas “réinstaller phpMyAdmin” : c’est ajouter l’hôte correspondant, puis supprimer l’ancien si nécessaire.
Problèmes CSRF phpMyAdmin : comprendre tokens, cookies et sessions (et ce qui les casse)
phpMyAdmin protège ses actions par des tokens anti-CSRF stockés en session et injectés dans les formulaires. Si la session change (nouveau PHPSESSID), si le cookie n’est pas renvoyé, ou si une page intermédiaire est servie depuis un cache, le token soumis ne correspond plus à celui attendu → erreur CSRF.
“Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated.”
— OWASP, CSRF (n.d.)
Concrètement : un phpMyAdmin exposé et mal protégé est une cible critique ; casser CSRF revient à rendre l’outil beaucoup plus dangereux.
Les causes terrain les plus courantes en 2026 :
- Cookie SameSite/Secure incohérent (migration HTTP→HTTPS, reverse proxy, sous-domaine différent). Un cookie
Securen’est pas envoyé en HTTP ; un mauvaisDomainfait que le navigateur le garde mais ne le renvoie jamais. - Cache proxy/CDN sur des pages dynamiques (Cloudflare, Varnish, cache LiteSpeed). Un HTML mis en cache avec un token ancien est un générateur de “token mismatch”.
- Sessions non persistantes en load-balancing : absence de sticky sessions,
session.save_handler=fileslocal différent par nœud, ou purge agressive de/tmp. - En-têtes proxy incomplets : si votre terminaison TLS est sur un reverse proxy mais que le backend “croit” être en HTTP, vous pouvez obtenir des redirections ou des cookies non conformes (ex. pas de
Secure) qui rendent la session instable.
En pratique, commencez par isoler : testez en navigation privée, sans extensions, sur une URL directe sans WAF, et comparez Set-Cookie / Cookie entre requête GET de login et POST du formulaire. Si le cookie de session n’est pas renvoyé, vous êtes sur un problème HTTP (headers, SameSite, HTTPS). Si le cookie est renvoyé mais que la session côté serveur n’existe plus, vous êtes sur un problème de stockage de sessions (permissions, GC, Redis down).
Un test simple (et souvent révélateur) : ouvrez deux onglets phpMyAdmin, connectez-vous, puis tentez une action dans le premier onglet après quelques minutes. Si ça casse aléatoirement, c’est rarement “MySQL” — c’est typiquement un mélange cache + sessions ou LB sans persistance.
(Et si vous souhaitez une lecture de référence côté sécurité applicative : page OWASP CSRF, lien unique externe utile : OWASP CSRF)
Corrections CSRF : checklist serveur (PHP), proxy (Nginx/Apache) et configuration phpMyAdmin
Côté PHP, les erreurs CSRF sont souvent des symptômes d’un problème de session. Vérifiez d’abord les basiques :
session.save_pathexiste et est inscriptible par l’utilisateur PHP-FPM.- Pas de purge cron agressive de
/var/lib/php/sessionsou/tmp. session.gc_maxlifetimecohérent avec votre usage (un back-office DB, ce n’est pas une session frontend de 5 minutes).
Ajoutez une vérification “bête mais efficace” : regardez si le serveur écrit réellement des fichiers de session (si files) au moment du login (date de modification qui bouge). Si rien ne s’écrit, cherchez permissions / open_basedir / noexec / quota disque. Une partition pleine peut se manifester par des effets de session incohérents… puis des tokens invalides.
En environnement multi-instance, arrêtez d’utiliser files si vous load-balancez : basculez vers Redis (session.save_handler=redis) ou activez le sticky session au niveau du LB. Sans ça, vous aurez des CSRF aléatoires, particulièrement visibles quand vous exécutez des actions POST (import/export) qui changent de nœud.
Côté proxy/cache, forcez l’absence de cache sur phpMyAdmin. Exemple Nginx (à adapter) :
location ^~ /phpmyadmin/ {
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always;
add_header Pragma "no-cache" always;
add_header X-Frame-Options "DENY" always;
}
Deux ajouts fréquents quand phpMyAdmin est derrière un TLS-terminator (LB, reverse proxy) :
- assurez-vous que le backend reçoit bien le schéma d’origine (
X-Forwarded-Proto https) ; - si vous forcez HTTPS, évitez les boucles : un
ForceSSLcôté phpMyAdmin + redirection proxy mal définie peut conduire à des enchaînements 301/302 qui perturbent les cookies et la session.
Si vous êtes derrière Cloudflare ou un WAF, assurez-vous qu’aucune règle de “Cache Everything” ne s’applique. Une page de login phpMyAdmin ne doit jamais être cachée. Sur le volet sécurité HTTP, la logique est identique à ce qu’on applique pour éviter l’intégration non autorisée (et donc réduire certaines surfaces d’attaque) : CSP frame-ancestors : empêcher le clickjacking et l’intégration non autorisée.
Côté phpMyAdmin enfin, vérifiez le mode d’authentification et la configuration crypto. En mode cookie, phpMyAdmin exige un secret : c’est un point de stabilité. Un secret qui change (déploiement, container recréé, nouveau config.inc.php généré) invalide les cookies et peut mimer un problème CSRF. Dans config.inc.php :
$cfg['blowfish_secret'] = '32+ caractères aléatoires, stable et secret';
$cfg['ForceSSL'] = true; // si vous êtes en HTTPS
Deux conseils de durabilité :
- si vous êtes en conteneurs, montez
config.inc.phpvia un volume persistant (ou une gestion de secrets) pour éviter qu’un redéploiement ne régénère la passphrase ; - évitez d’exposer phpMyAdmin sur plusieurs FQDN (ex.
admin.domaine.tldetdomaine.tld/phpmyadmin) : les variations deDomain/Pathde cookie peuvent créer des comportements “fantômes”.
Évitez aussi les bricolages du type “supprimer la vérification CSRF” (patch core). Si vous êtes dans ce cas, c’est que votre stack réseau/session est cassée ; corrigez-la, sinon la prochaine étape c’est un incident sécurité.
Fiabiliser l’accès à phpMyAdmin en production : surface d’attaque, journalisation, alternatives
phpMyAdmin est un outil d’administration généraliste. En production e-commerce, son exposition publique est un compromis risqué. Le minimum : restreindre par IP, protéger par auth HTTP en plus de l’auth MySQL, et idéalement le rendre accessible uniquement via VPN / bastion. Moins l’interface est atteignable, moins vous dépendez de la perfection de toutes les couches (PHP, cookies, tokens, WAF).
Checklist “anti-drame” (sans complexifier inutilement) :
- Autoriser uniquement vos IP (bureau/VPN) au niveau Nginx/Apache ou du firewall.
- Ajouter une authentification HTTP basique (deuxième barrière, très efficace contre le bruit).
- Mettre phpMyAdmin sur une URL non évidente (ça ne remplace pas l’IP filtering, mais réduit le scan opportuniste).
- Tenir phpMyAdmin à jour (5.2.x est un bon socle, mais appliquez les patchs).
Ensuite, journalisez correctement pour arrêter de “deviner”. Activez temporairement le general log MySQL lors d’un incident (puis désactivez, ça peut être coûteux), et corrélez avec les logs PHP-FPM. Si vous voyez des requêtes de login répétées, des rotations de session, ou des 302/403 inattendus, vous aurez un chemin clair. Les erreurs HTTP (ex. 503/timeout) peuvent aussi interrompre des POST et provoquer des comportements de session étranges ; la méthode de diagnostic log est similaire à : Erreur HTTP 503 : diagnostiquer PHP et logs Apache/LiteSpeed.
Enfin, si votre objectif est simplement de manipuler une base PrestaShop (export, requêtes ponctuelles, inspections), considérez des alternatives plus “ops-friendly” : accès mysql via SSH, mysqldump/mysqlpump, ou une UI interne derrière VPN. phpMyAdmin reste utile, mais il ne doit pas devenir un point unique de défaillance. Pour les environnements en migration (MySQL 5.7→8.0, ou MariaDB évolutif), gardez une procédure de staging et de tests, car les changements d’auth et de plugin reviennent vite dans les #1045 : MySQL migration 5.7 vers 8 : procédure, staging et tests de charge.
En résumé opérationnel : #1045 se corrige dans MySQL (user/host/plugin/grants), CSRF se corrige dans la chaîne HTTP/session (cookies, cache, LB, session.save_handler). Si vous traitez les deux comme un seul problème “phpMyAdmin marche pas”, vous allez osciller entre des changements dangereux (droits trop larges) et des contournements cassant la sécurité (désactivation CSRF).
