简体   繁体   中英

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

I figured out the solution below. I've left a second update for more clarification.

Context

I've got a Discord bot, written in JavaScript using the discord.js library, that I've been working on by myself for nearly two years. I started using MySQL for database queries and such just over a year ago. This was on my local Windows 10 machine. As this was a small hobby project at the time, I wasn't too worried about only having one MySQL instance for both development and production. Finally, about 9 months ago, I was able to get the bot up and running on my Linode server, which runs Ubuntu 18.04, along with a copy of the MySQL database running there.

Up until now, with this setup, things have worked smoothly. I use the local database on my Windows PC for development and testing, and then I push updates to the Ubuntu 18.04 server on Linode where the production database is. Also, just in case this helps, I do run the bot locally on my PC when doing development. There's two Discord bots with two unique tokens (one for production and one for development) so that I can keep the production one running while I work on updates. I don't have the development bot running on the server 24/7 like the production bot.

Recently, however, a friend of mine (a self-proclaimed "for-loop extraordinaire") has started helping me with the development. As such, we think now is a good time to have the development database active 24/7 as well, so that he may work on the bot whether I'm around or not. This is where we get to the problem.

The Issue

I've left an update below as I've switched to the mysql2 package to try and find a solution.

So, in case it wasn't obvious, my goal here is very simple: I want my bot (when run locally on my, or my friend's, Windows machine using node.js) to connect to the remote database hosted on my Ubuntu 18.04 server, which is in the cloud , not my local.network. I'm not afraid to admit that I'm far from a good web developer, so I don't know the logistics or the ins and outs of how this stuff really works. It's a wonder I've made it this far. But I thought it would be as simple as when connecting to a local MySQL instance. However, when I run the code, the console spits this error out at me.

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
}

Here's how my code is currently set up:

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!")
})

This method worked flawlessly when host was localhost (obviously) but when trying to connect remotely to the server on Linode, it just refuses. I've tried both the Linode URL ( example.com ) as well as the IP ( LINODE.IP.ADDRESS.HERE ) address, both giving me the same error. Also I am aware that the mysql2 package for Node exists, I just haven't switched over yet. If switching over would in fact help with this problem, please let me know.

Solutions I've Tried

I've tried multiple answers from multiple similar questions on this site, such as this one and this , however none of the solutions work (including adding socketPath or changing port , etc.)

I've tried changing the bind-address in the mysqld.cnf file to 0.0.0.0 and * , both of which did allow the bot to connect to the database, however access was still denied to actually read the database itself. All I know is that it at least connected (though trying it again now has left me with an error message this time)

  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 is up to date so could this have to do with me not using mysql2 ? I'm not a fan of this option, regardless, but I thought I'd try it at least.

My last resort was to create an SSH tunnel to connect to the database. Again, I'm still a web development novice, so I didn't fully know what I was doing, but I followed this guide here , but replacing the code I needed to, and ended up with a completely separate SSH connection error. If SSH is absolutely required to accomplish what I want, then please let me know and I'll open a new question regarding that. I just wanted to mention it here to show that I have at least tried.

UPDATE

I've switched to using mysql2 , and while the error message is cleaner, it still persists.

I've attempted Archil's solution , and while it doesn't do much now that I've switched to mysql2 , it did provide me with a better understanding of MySQL's authentication system, which lead me to switch in the first place. Unfortunately, both Archil's answer and the mysql2 upgrade give me the same error:

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

...despite the fact that I have granted 'root'@'%' all privileges.

Regardless, again, this isn't my preferred way of doing this anyway. If there's a more secure solution I'll gladly take it. I'll continue to try different solutions now that I have mysql2 installed.

UPDATE 2

After looking further into it, I figured out that permissions were NOT set up like I thought they were for the user I was trying to connect to the server with. Once I fixed that, it did connect, but one of the tables that gets queried when the bot starts was showing as empty. Turns out it didn't exist!

I had made a copy of the production database as a base for the new development one. Problem was, it was missing a table that was on my local (old) development database. This lead to me believing that the bot was connecting with MySQL but not reading anything from the database. I've added the correct table, and it works great, I've left a solution with more specific steps below. in case this page is ever found by another novice web developer like me. Thanks for the help!

I've left a second update as to how I got to this solution.

In short, setting the bind-address to 0.0.0.0 does work. If you're using the original mysql package, you'll need to follow Archil's solution . 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 of the user you're trying to connect with using:

SHOW GRANTS FOR 'user'@'%';

Assuming you're trying to connect remotely like I was, you'll need to create a user with the '%' wildcard if you haven't.

At this point it should connect, as it does for me, and if there's any errors after that, it's probably something to do with the tables within the database itself.

I've answer https://stackoverflow.com/a/50547109/4089212

Check please. You need to change auth mode for mySQL.

In my case (mariadb) I've managed to change the bind address to 0.0.0.0 in the file:

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

After a restart I've managed to connect to the database:

service mysql restart

You may need to search for the correct file to edit in the folder /etc/mysql/mariadb.conf.d/

Just look for bind-address (may have an IP address like 127.0.0.1)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM