環境
% sw_vers ProductName: macOS ProductVersion: 12.4 BuildVersion: 21F79 % node -v v18.4.0 % mysql --version mysql Ver 8.0.30 for macos12.4 on x86_64 (Homebrew) % brew -v Homebrew 3.5.9 Homebrew/homebrew-core (git revision 27007d7668a; last commit 2022-08-20) Homebrew/homebrew-cask (git revision d2da3c1a45; last commit 2022-08-20)
概要
MySQLの設定ファイルmy.cnf
に以下の記載
bind-address = 127.0.0.1
がある場合に、node(のmysql2
パッケージ)でhost
にlocalhost
を指定して接続しようとすると失敗します。
なので、localhost
ではなく、直接127.0.0.1
を指定します。
const mysql = require('mysql2'); const connection = mysql.createConnection({ host: '127.0.0.1', // localhostだとダメ user: 'root', database: 'hoge' });
調べたこと
特にHomebrewでMySQLをインストールした人がこの問題に直面しているかと思います。
HomebrewでMySQLをインストールすると、自動で設定ファイルmy.cnf
が作成されます:
% cat /usr/local/etc/my.cnf # Default Homebrew MySQL server config [mysqld] # Only allow connections from localhost bind-address = 127.0.0.1 mysqlx-bind-address = 127.0.0.1
コメント文からもわかるように、bind-address
にIPアドレスを指定すると、そのアドレス以外からのアクセスを禁止します。
基本的に、127.0.0.1
にはlocalhost
というホスト名が設定されています:
% cat /etc/hosts ## # Host Database # # localhost is used to configure the loopback interface # when the system is booting. Do not change this entry. ## 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost
なので、上記のようにbind-address
の設定がされていても、localhost
からでもアクセスできるはずです。
実際、ターミナルからであれば、localhost
でログインできます:
% mysql.server start Starting MySQL .. SUCCESS! % mysql -u root -h localhost Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 14 Server version: 8.0.30 Homebrew 略 mysql>
ところが、nodeの方では、ホスト名にlocalhost
を指定してMySQLに接続しようとすると失敗します。
下記内容のファイルをtest.js
という名前で保存:
const mysql = require('mysql2'); const connection = mysql.createConnection({ host: 'localhost', user: 'root', password: '' }); connection.query( 'SELECT 1 + 1', function(err, results) { console.log(results); } ); connection.end();
実行してみると、エラーが出る:
% node test.js undefined node:events:515 throw er; // Unhandled 'error' event ^ Error: connect ECONNREFUSED ::1:3306 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1237:16) Emitted 'error' event on Connection instance at: at Connection._notifyError (/Users/hoge/test/node_modules/mysql2/lib/connection.js:236:12) at Connection._handleFatalError (/Users/hoge/test/node_modules/mysql2/lib/connection.js:167:10) at Connection._handleNetworkError (/Users/hoge/test/node_modules/mysql2/lib/connection.js:180:10) at Socket.emit (node:events:537:28) at emitErrorNT (node:internal/streams/destroy:151:8) at emitErrorCloseNT (node:internal/streams/destroy:116:3) at process.processTicksAndRejections (node:internal/process/task_queues:82:21) { errno: -61, code: 'ECONNREFUSED', syscall: 'connect', address: '::1', port: 3306, fatal: true } Node.js v18.4.0
上記コードのlocalhost
部分を127.0.0.1
に置き換えます:
// host: 'localhost', host: '127.0.0.1',
再度実行してみると、ちゃんとクエリが実行されました:
% node test.js [ { '1 + 1': 2 } ]
これは奇妙ですね。mysql2
パッケージがブラックボックスなのでこれ以上何とも言えません。
node + MySQLの解説記事を見ていると、ほとんどの記事でhost: 'localhost'
と書いています。
おそらく、それでクエリ実行できているのは、my.cnf
にbind-address
の記載がないからでしょう。
あるいはバージョンの違いでしょうか。そこまでは調べられていません。
とにかく、HomebrewでMySQLをインストールするとmy.cnf
にbind-address
の設定が自動で作成されてしまいますので、その設定をコメントアウトするか、host
に直接127.0.0.1
を指定するかのいずれかの対応が必要になります。
以上。
補足
"mysql2"パッケージ
nodeでMySQL接続するためのパッケージですが、mysql
ではなくmysql2
を使っているのは、前者がMySQL 8系に非対応だからです。
私はそもそも初心者で何も知らないのですが、mysql2
はmysql
と同じように使えるらしいです(メソッド名とかが同じ?)。
my.cnfの場所
my.cnf
が配置されうる場所は以下のようにして調べられるらしいです:
% mysql --help | grep "/my.cnf" /etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf
HomebrewでMySQLをインストールしたときに作成されるのは/usr/local/etc/my.cnf
のみです。
他の3つもcat
してみましたが、いずれもファイルが存在していませんでした。
なお、既に/usr/local/etc/my.cnf
が存在している状態で、brew install mysql
したときは、/usr/local/etc/my.cnf
に変更は加わりません。
なので昔にMySQLの環境を作っていた人は、Homebrewからインストールし直しても上記問題には気がつかなかったかも知れません。
ちなみに、brew uninstall mysql
してもこの設定ファイルは消去されないので、いらなくなったら手動で削除して下さい:
rm /usr/local/etc/my.cnf
参考
MySQL 8系ではmysql
ではなくmysql2
を使わないとダメだと気付かせてくれたサイト
mysql2
パッケージ
同様のエラーに対し試行錯誤している記事。これ読んで下さい
インストールしたMySQLを完全に消したい記事。いつか必要になるかも