Node.js + MySQL:程序拒绝使用 "ECONNREFUSED" 连接到远程数据库

Node.js + MySQL: Program refuses to connect to remote database with "ECONNREFUSED"

我找到了以下解决方案。我已经留下了第二次更新以进行更多说明。

上下文

我有一个 Discord 机器人,它是使用 discord.js 库用 JavaScript 编写的,我自己已经为此工作了将近两年。一年多以前,我开始使用 MySQL 进行数据库查询等。这是在我本地的 Windows 10 机器上。由于当时这是一个业余爱好项目,我并不太担心只有一个 MySQL 实例用于开发和生产。最后,大约 9 个月前,我能够在我的 Linode 服务器上启动并 运行ning,运行s Ubuntu 18.04,以及 MySQL数据库运行宁那里。

到目前为止,通过此设置,一切都进行得很顺利。我在 Windows PC 上使用本地数据库进行开发和测试,然后将更新推送到生产数据库所在的 Linode 上的 Ubuntu 18.04 服务器。此外,为了以防万一这有帮助,我在进行开发时 运行 在我的 PC 上本地执行 bot。有两个 Discord 机器人有两个独特的令牌(一个用于生产,一个用于开发),这样我就可以在进行更新时保持生产一个 运行ning。我没有开发机器人 运行 像生产机器人那样在服务器上 24/7 全天候运行。

然而,最近,我的一个朋友(自称“for-loop 非凡者”)开始帮助我进行开发。因此,我们认为现在也是让开发数据库 24/7 处于活动状态的好时机,这样无论我在不在,他都可以在机器人上工作。这就是我们遇到问题的地方。

问题

我在下面留下了一个更新,因为我已经切换到 mysql2 包以尝试找到解决方案。

所以,如果不是很明显,我的目标很简单:我想要我的机器人(当 运行 在我或我朋友的 Windows 本地机器上使用 node.js) 连接到我的 Ubuntu 18.04 服务器上托管的远程数据库,它在云端 ,而不是我的本地网络。我不怕承认我离一个优秀的 Web 开发人员还差得很远,所以我不知道这些东西真正运作的逻辑或来龙去脉。我能走到这一步真是奇迹。但我认为它会像连接到本地 MySQL 实例一样简单。但是,当我 运行 代码时,控制台向我吐出这个错误。

Error: connect ECONNREFUSED LINODE.IP.ADDRESS.HERE:3306
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16)
    --------------------
    at Protocol._enqueue (D:\Users\path\node_modules\mysql\lib\protocol\Protocol.js:144:48)
    at Protocol.handshake (D:\Users\path\node_modules\mysql\lib\protocol\Protocol.js:51:23)
    at Connection.connect (D:\Users\path\node_modules\mysql\lib\Connection.js:119:18)
    at Object.<anonymous> (D:\Users\path\bot\index.js:118:5)
    at Module._compile (internal/modules/cjs/loader.js:1138:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
    at Module.load (internal/modules/cjs/loader.js:986:32)
    at Function.Module._load (internal/modules/cjs/loader.js:879:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47 {
  errno: 'ECONNREFUSED',
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: 'LINODE.IP.ADDRESS.HERE',
  port: 3306,
  fatal: true
}

这是我的代码当前的设置方式:

const mysql = require("mysql")
//CONNECT TO MYSQL
var con = mysql.createConnection({
    host: 'example.com',
    port: 3306,
    user: 'user',
    password: 'pass',
    database: 'botDB',
    charset: "utf8mb4"
});

//CONNECTED TO DATABASE
con.connect(err => {
    if (err) { throw err };
    console.log("My database is up and running!")
})

hostlocalhost 时(显然),此方法完美无缺,但当尝试远程连接到 Linode 上的服务器时,它只是拒绝。我已经尝试了 Linode URL (example.com) 以及 IP (LINODE.IP.ADDRESS.HERE) 地址,都给了我同样的错误。我也知道 Node 的 mysql2 包存在,我只是还没有切换。如果切换实际上有助于解决这个问题,请告诉我。

我尝试过的解决方案

我已尝试从该站点上的多个类似问题中找到多个答案,例如 this one and this,但是 none 的解决方案有效(包括添加 socketPath 或更改 port, 等等)

我尝试将 mysqld.cnf 文件中的 bind-address 更改为 0.0.0.0*,这两者都允许机器人连接到数据库,但是访问仍然被拒绝实际读取数据库本身。我所知道的是它至少连接了(虽然现在再次尝试这一次给我留下了一条错误消息)

  code: 'ER_NOT_SUPPORTED_AUTH_MODE',
  errno: 1251,
  sqlMessage: 'Client does not support authentication protocol requested by server; consider upgrading MySQL client',
  sqlState: '08004',
  fatal: true

MySQL 是最新的所以这与我没有使用 mysql2 有关系吗?无论如何,我不喜欢这个选项,但我想我至少会尝试一下。

我最后的办法是创建一个 SSH 隧道来连接到数据库。同样,我还是一个网络开发新手,所以我并不完全知道我在做什么,但是我按照this guide here,但是替换了我需要的代码,结果出现了一个完全独立的 SSH 连接错误.如果 SSH 绝对需要 来完成我想要的,那么请告诉我,我将就此提出一个新问题。我只是想在这里提一下,以表明我至少尝试过。

更新

我已经改用 mysql2,虽然错误消息更清晰了,但它仍然存在。

我已经尝试过 ,虽然现在我已经切换到 mysql2 并没有太大作用,但它确实让我更好地理解了 MySQL的身份验证系统,这导致我首先切换。不幸的是,Archil 的回答和 mysql2 升级都给我同样的错误:

{
  code: 'ER_ACCESS_DENIED_ERROR',
  errno: 1045,
  sqlState: '28000',
  sqlMessage: "Access denied for user 'root'@'MY.LOCAL.IP.ADDRESS' (using password: YES)"
}

...尽管我已授予 'root'@'%' 所有权限。

无论如何,这不是我首选的方式。如果有更安全的解决方案,我会很乐意接受。既然我已经安装了 mysql2,我将继续尝试不同的解决方案。

更新 2

在进一步调查之后,我发现权限设置并不像我认为的那样是为我尝试连接到服务器的用户设置的。一旦我修复了它,它确实连接了,但是当机器人启动时被查询的 table 之一显示为空。原来它不存在!

我复制了一份生产数据库作为新开发数据库的基础。问题是,它在我的本地(旧)开发数据库中缺少 的 table。这让我相信该机器人正在连接 MySQL 但没有从数据库中读取任何内容。我添加了正确的 table,效果很好!我在下面留下了一个包含更具体步骤的解决方案,以防其他像我这样的 Web 开发新手找到此页面。感谢您的帮助!

我已经回答了

请检查。 您需要更改 mySQL.

的授权模式

关于如何得到这个解决方案,我已经进行了第二次更新。

简而言之,将 bind-address 设置为 0.0.0.0 确实有效。如果您使用的是原始 mysql 软件包,则需要关注您尝试联系的用户的 . If you're using mysql2 and there's still an error (or if Archil's answer doesn't work with mysql), make sure you double-check the permissions 使用:

SHOW GRANTS FOR 'user'@'%';

假设您正像我一样尝试远程连接,如果您还没有,则需要使用“%”通配符创建一个用户。

此时它应该可以连接,就像我一样,如果之后有任何错误,可能与数据库本身内的表有关。

在我的例子 (mariadb) 中,我已经设法将文件中的绑定地址更改为 0.0.0.0:

sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf

重启后我成功连接到数据库:

service mysql restart

您可能需要在文件夹 /etc/mysql/mariadb.conf.d/

中搜索要编辑的正确文件

只需查找绑定地址(可能有一个像 127.0.0.1 这样的 IP 地址)