首页 > 解决方案 > Node.js + MySQL:程序拒绝使用“ECONNREFUSED”连接到远程数据库

问题描述

我想出了下面的解决方案。我留下了第二次更新以获得更多说明。

语境

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

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

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

问题

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

所以,如果不是很明显,我的目标很简单:我希望我的机器人(当我使用 node.js 在我或我朋友的 Windows 机器上本地运行时)连接到托管在我的 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!")
})

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

我尝试过的解决方案

我已经尝试了该站点上多个类似问题的多个答案,例如this onethis,但是没有一个解决方案有效(包括添加socketPath或更改port等)

我尝试将文件bind-address中的更改为and ,这两者都允许机器人连接到数据库,但是仍然拒绝访问以实际读取数据库本身。我所知道的是它至少已连接(尽管现在再次尝试给我留下了一条错误消息)mysqld.cnf0.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 隧道来连接到数据库。同样,我仍然是 Web 开发新手,所以我并不完全知道自己在做什么,但我在这里遵循了本指南,但替换了我需要的代码,并最终导致了一个完全独立的 SSH 连接错误。如果绝对需要SSH来完成我想要的,那么请告诉我,我会就此提出一个新问题。我只是想在这里提一下,以表明我至少尝试过。

更新

我已切换到 using mysql2,虽然错误消息更清晰,但它仍然存在。

我已经尝试了Archil 的解决方案,虽然现在我切换到它并没有多大作用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

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

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

标签: mysqlnode.jsdiscord.jsubuntu-18.04linode

解决方案


关于如何获得此解决方案,我已经留下了第二次更新。

简而言之,设置bind-addressto0.0.0.0确实有效。如果您使用的是原始mysql包,则需要遵循Archil 的解决方案。如果您正在使用mysql2并且仍然存在错误(或者如果 Archil 的答案不适用于mysql),请确保您仔细检查您尝试连接的用户的权限:

SHOW GRANTS FOR 'user'@'%';

假设您尝试像我一样进行远程连接,如果您没有创建一个带有“%”通配符的用户,那么您需要创建一个用户。

此时它应该连​​接,就像它对我所做的那样,如果在那之后有任何错误,这可能与数据库本身的表有关。


推荐阅读