Logo MySQL

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.