Вопрос или проблема
Я столкнулся с проблемой, которую, несмотря на некоторые исследования и различные попытки устранения неполадок, не смог решить или действительно понять. Я подозреваю, что проблема связана с поведением MySqlConnector.
Мы запускаем приложение на dotnet в системе Linux и хотим подключиться к базе данных MySQL на той же системе. Пользователь, которого мы используем, может подключаться только с localhost.
Вот вывод:
2025-01-06 13:41:36.819 +01:00 [INF] OpenConnection =>
Host=localhost;Username=myuser;Password='mypass';Database=; Connection Timeout=360;Allow User Variables=True
2025-01-06 13:41:37.460 +01:00 [ERR] Error connecting to mysql server AccessDenied
MySqlConnector.MySqlException (0x80004005): Access denied for user 'myuser'@'10.15.15.142' (using password: YES)
at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 885
IP-адрес, который виден (10.15.15.142), это IP-адрес LAN, назначенный первому интерфейсу системы. Здесь я теряюсь, мы указываем подключение к localhost, но MySQL видит подключение как идущее с этого IP-адреса. Почему?
Открытие оболочки и введение “mysql -u myuser -p” позволит подключиться без проблем.
Исследование предположило принудительное использование Unix-сокета для подключения, указывая “Protocol=unix”, но это не привело к улучшению:
2025-01-06 14:05:53.176 +01:00 [INF] OpenConnection =>
Host=localhost;Username=myuser;Password='mypass';Database=; Connection Timeout=360;Allow User Variables=True;Protocol=unix
2025-01-06 14:05:53.263 +01:00 [ERR] Error connecting to mysql server Failed
MySqlConnector.MySqlException (0x80004005): Cannot find Unix Socket at localhost
Мы также пробовали использовать 127.0.0.1 вместо localhost для строки подключения, но результат тот же. Также проверили, что файл hosts в системе настроен правильно. Мы также подтвердили, что смена пользователя на myuser@% работает как положено, но как только она изменяется на myuser@localhost, проблема возвращается.
Версии:
Microsoft.AspNetCore.App 7.0.20 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 6.0.36 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.20 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
mysql Ver 8.0.35 for Linux on x86_64 (MySQL Community Server - GPL)
Когда пакеты поступают из одного источника, их сопровождающие пытаются сделать так, чтобы все работало без проблем. Но похоже, что .NET клиентская библиотека, вероятно, поступает не из того же источника, что и MySQL серверный пакет. У каждого пакета есть некоторые настройки по умолчанию — пути и так далее, и в данном случае некоторые из этих настроек не совпадают.
Одной из таких настроек, которую мы обнаружили, является путь к Unix-сокету по умолчанию. Должен быть способ его указать, так что в общем случае, когда говорится, что сокет не найден, но другая программа (консольный клиент mysql) может его найти, вы можете просто указать путь, и это должно сработать.
Еще одно различие заключается в том, что “стандартный” libmysqlclient автоматически переключается на Unix-сокеты, когда он видит localhost, но ваша клиентская библиотека этого не делает, поэтому ей нужно указать использовать Unix-сокеты.
Наконец, обратите внимание на нетривиальное поведение предоставления доступа в отношении имен хостов. Ваши таблицы предоставления MySQL, вероятно, содержат предоставления для username@localhost
, а не для username@whatever
или подстановки username@%
. Такие предоставления для localhost определенно работают, когда вы подключаетесь через Unix-сокет. Они также должны работать для TCP от localhost к localhost, но это зависит от разрешения имен, и необычные настройки разрешения имен могут делать его похожим на что-то другое, даже когда вы, кажется, используете адреса localhost. Например, ваше соединение может исходить от 127.0.1.1, который может быть связан с каким-то альтернативным именем в файле hosts, так что когда происходит обратное разрешение на сервере, происходит вывод этого альтернативного имени вместо localhost, и сервер не распознает соединение как исходящее от localhost и не применяет доступы для localhost.
Ответ или решение
Проблема, с которой вы столкнулись, связана с тем, как MySqlConnector обрабатывает подключение к MySQL-серверу на том же самом хосте. Несмотря на указание ‘localhost’ в строке подключения, сервер воспринимает попытку подключения как исходящую с IP-адреса вашей системы в локальной сети. Давайте рассмотрим возможные причины и решения этой проблемы.
Теория:
-
Протокол подключения: Когда MySQL клиент сталкивается с ‘localhost’, он часто переключается на использование Unix-сокетов по умолчанию. Однако не все клиентские библиотеки выполняют такое переключение автоматически. Это может привести к попытке установить соединение через сетевой интерфейс, что выявляется в виде LAN-адреса.
-
Разрешение имён: Ваш сервер может выполнять обратное разрешение имён, и если одна из записей hosts связана с другим именем, а не с ‘localhost’, это может влиять на распознавание подключения как исходящего с ‘localhost’.
-
Путь Unix-сокета: Пакеты и библиотеки могут иметь разные настройки по умолчанию, включая места расположения сокетов. Отсутствие заданного пути может приводить к ошибке подсистемы Unix-сокетов.
Пример:
Возьмем два приложения: одно, использующее стандартный MySQL клиент в командной строке, и другое – dotnet приложение с использованием MySqlConnector. Первое приложение успешно подключается через локальный Unix-сокет, в то время как второе сталкивается с ошибкой из-за использования IP-адреса. В первом случае соединение происходит через сокеты, а во втором через TCP/IP.
Применение:
-
Настройка Unix-сокетов: Во-первых, попробуйте указать точный путь к Unix-сокету в вашей строке подключения. Обычно MySQL использует путь вроде
/var/run/mysqld/mysqld.sock
, но это можно уточнить в конфигурации MySQL или черезmysqladmin variables|grep socket
. -
Явное указание протокола подключения: Добавлеите не только
Protocol=unix
в вашу строку подключения, но и укажите параметрUnixSocket=/путь/к/sock
, чтобы принудительно использовать сокеты. -
Проверка и настройка файла hosts: Убедитесь, что файл
/etc/hosts
корректно содержит запись для ‘localhost’. Это должно исключить возможность, что обратное разрешение приводит к получению неверного имени хоста. -
Изменение разрешений доступа: Если возможно, создайте пользователя
myuser
с разрешением наmyuser@127.0.0.1
, чтобы обойти проблему с некорректным разрешением имен при работе через TCP/IP.
Настройка вышеперечисленных параметров позволит вашему dotnet приложению подключаться к MySQL серверу через Unix-сокеты на том же хосте, используя корректные права доступа и избегая проблем с сетью.