Je travaille sur MacOS. Ce dernier n’ayant pas de gestionnaire de paquets intégré, j’utilise Homebrew comme gestionnaire de paquets et de services. Les différentes étapes décrites dans cet article sont spécifiques à cet environnement. Mais les conclusions et mes erreurs ne le sont pas.
Hier, au moment de travailler sur cet environnement, je me suis retrouvé dans l’incapacité de me connecter à MySQL installé localement, avec cette erreur :
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
Celle-ci indique généralement que le serveur MySQL n’est pas lancé, ou dans mon cas, pas correctement. Retraçons cette séance d’analyse.
Symptôme initial : un service démarré, mais muet
La première chose à faire est de vérifier l’état du service :
brew services list
Name Status User File
mysql started benjamin ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
Le service est bien démarré, mais l’erreur persiste. Vérifions ce qu’il se passe au niveau du système, et plus précisément des processus mysql(d) :
ps aux | grep mysql
benjamin 15417 98,6 0,2 412228960 26752 s001 R 5:10 42:32.01 /opt/homebrew/Cellar/mysql/9.3.0/bin/mysqld ...
benjamin 18133 0,0 0,0 410617632 704 s000 S+ 8:06 0:00.01 tail -f -n0 ...
benjamin 15306 0,0 0,0 410736048 832 s001 S 5:10 0:00.02 /bin/sh /opt/homebrew/Cellar/mysql/9.3.0/bin/mysqld_safe --datadir=/opt/homebrew/var/mysql --pid-file=/opt/homebrew/var/mysql/macbookpro.home.pid
benjamin 22579 0,0 0,0 410724256 1408 s002 S+ 8:18 0:00.00 grep mysql
benjamin 20736 0,0 1,9 411681984 320848 ?? S 8:16 0:00.41 /opt/homebrew/opt/mysql/bin/mysqld --basedir=/opt/homebrew/opt/mysql --datadir=/opt/homebrew/var/mysql --plugin-dir=/opt/homebrew/opt/mysql/lib/plugin --log-error=macbookpro.home.err --pid-file=macbookpro.home.pid
benjamin 20634 0,0 0,0 410604896 3104 ?? S 8:16 0:00.03 /bin/sh /opt/homebrew/opt/mysql/bin/mysqld_safe --datadir=/opt/homebrew/var/mysql
On peut ici voir plusieurs processus mysql(d) en cours d’exécution, dont un qui consomme près de 100% de CPU (PID 15417). Sachant que la connexion au socket ne fonctionne pas et que le processus utilisant 100% de CPU, on peut en déduire que celui-ci semble occupé à autre chose qu’à nous répondre.
On trouve également dans les logs l’entrée suivante à répétition.
[ERROR] [MY-012574] [InnoDB] Unable to lock ./ibdata1 error: 35
Cette erreur indique que le processus n’arrive pas à obtenir un lock. Cela peut venir d’un problème de permission, de disque, ou indiquer que le lock est déjà utilisé par un autre processus. Autre processus que l’on voit bien dans le résultat de la commande ps
plus haut, lancé depuis /opt/homebrew/opt/mysql/bin/mysqld
(PID 20736), alors que homebrew gère le service mysql depuis un script mysqld_safe
qui lance ensuite mysqld
depuis le répertoire propre à sa version, à savoir /opt/homebrew/Cellar/mysql/9.3.0/bin/
dans mon cas.
On note donc un comportement anormal ici.
Il a fallu arrêter le service avec la commande brew services stop mysql
, et vérifier les processus en cours d’exécution. Le processus 20736 était toujours présent, non tué par l’arrêt du service. On le tue manuellement avec kill -9
, vu qu’il ne voulait pas être conciliant avec un simple kill
.
Nouvelle piste : Les agents de lancement (LaunchAgents)
Les Launch Agents sur MacOS sont l’équivalent des services systemd sur Linux. On retrouve des fichiers .plist
au format xml qui sont l’équivalent des fichiers .service
pour systemd.
On peut les retrouver à différents endroits du système :
~/Library/LaunchAgents
/Library/LaunchAgents
/System/Library/LaunchDaemons
, non pertinent ici dans la mesure où nous sommes dans le cadre d’une installation utilisateur.
Dans notre cas, le fichier créé par Homebrew est ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>homebrew.mxcl.mysql</string>
<key>LimitLoadToSessionType</key>
<array>
<string>Aqua</string>
<string>Background</string>
<string>LoginWindow</string>
<string>StandardIO</string>
<string>System</string>
</array>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/opt/mysql/bin/mysqld_safe</string>
<string>--datadir=/opt/homebrew/var/mysql</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>/opt/homebrew/var/mysql</string>
</dict>
</plist>
Celui-ci pointe bien vers mysqld_safe
. L’erreur ne semble donc pas se situer au niveau du Launch Agent, d’autant plus que le fichier /opt/homebrew/var/mysql/macbookpro.home.err
ne contenait aucune entrée indiquant une erreur.
Prochain suspect : le script mysqld_safe
La lecture du script mysqld_safe
dans /opt/homebrew/opt/mysql/bin
m’a permis de m’assurer que c’est bien le bon exécutable mysqld qui était lancé :
MY_BASEDIR_VERSION='/opt/homebrew/Cellar/mysql/9.3.0'
ledir='/opt/homebrew/Cellar/mysql/9.3.0/bin'
J’ai donc lancé mysqld_safe
manuellement :
/opt/homebrew/opt/mysql/bin/mysqld_safe --datadir=/opt/homebrew/var/mysql --log-error=macbookpro.home.err --pid-file=/opt/homebrew/var/mysql/macbookpro.home.pid &
Le comportement est resté inchangé, plusieurs processus mysql(d), dont un qui consomme énormément de ressources, et un processus lancé depuis /opt/homebrew/opt/mysql/bin/
.
Les liens symboliques en cause ?
J’ai vérifié que les différents exécutables n’avaient pas été remplacés par des liens symboliques, ce qui aurait pu expliquer ce processus non désiré lancé depuis le mauvais emplacement. Rien de ce côté non plus.
Seule solution : une réinstallation complète
Pour désinstaller complètement mysql avec homebrew, il suffit de faire ceci :
brew services stop mysql
brew uninstall --force mysql
brew cleanup
rm -rf /opt/homebrew/var/mysql
rm -rf /opt/homebrew/opt/mysql
Puis, pour le réinstaller :
brew install mysql
brew services start mysql
Et tout est rentré dans l’ordre, sans réelle explication.
Seule solution sans explication : vraiment ?
En réalité, la solution est apparue au moment de la désinstallation, lors de l’exécution de brew uninstall --force mysql
qui m’a retourné ceci :
Uninstalling mysql... (333 files, 291.9MB)
Error: Could not remove mysql keg! Do so manually:
sudo rm -rf /opt/homebrew/Cellar/mysql/9.3.0
Une petite vérification sur le dossier /opt/homebrew/Cellar/mysql/9.3.0
m’a permis de voir que l’utilisateur n’a pas les droits sur celui-ci alors que ce devrait être le cas.
La seule chose qui, selon moi et dans ce cas précis, a pu modifier les droits sur ce dossier, c’est une erreur lors du lancement du service. Je remonte l’historique de mon terminal jusqu’à tomber sur cette ligne :
sudo brew services start mysql
Tout venait de là ! Homebrew gère tout au niveau de l’utilisateur, et j’avais par erreur d’inattention lancé le service avec sudo
. Lancer le service de cette façon aura fait prendre les droits sur le dossier à l’utilisateur root, et causant tous ces dysfonctionnements. Une erreur due à l’habitude. Une erreur qui m’a fait perdre deux heures.