How To Use MySQL with NodeJS?
Learn to use MySQL with NodeJS for web apps in 2025. Step-by-step tutorial for developers.
It's very easy to use MySQL with Node.js. The following post is a quick look at the MySQL module for Node. There are currently two popular approaches for connecting with MySQL from Node.js: the original mysql package and the newer mysql2 (which supports promises). In this post we will cover the classic mysql usage (your original code), then add modern, production-friendly improvements using environment variables, error handling, and async/await with mysql2.
I’m assuming you have Node.js installed on your system. If not, see: How to install Node.js.
Installation of mysql package
First, install the MySQL driver with npm:
npm install mysql
To use it in your application file (e.g., app.js):
var mysql = require('mysql');
Creating MySQL Connection
Create a connection and define host, username, password and database:
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '123456',
database : 'nodedemo'
});
Open the connection:
connection.connect();
MySQL Query
Example query. To protect against SQL injection use parameter placeholders or connection.escape():
var queryString = 'SELECT * FROM users';
connection.query(queryString, function(err, rows, fields) {
if (err) {
throw err;
} else {
console.log(rows);
}
});
Loop through rows:
connection.query(queryString, function(err, rows, fields) {
if (err) throw err;
for (var i in rows) {
console.log('Username: ', rows[i].username);
}
});
Closing connection
Close using:
connection.end();
Or with callback:
connection.end(function(err) {
// Actions after connection closed
});
Connection Pooling in MySQL with Node.js
For high-traffic apps, use connection pooling to reuse connections instead of creating a new one per request:
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'localhost',
user : 'root',
password : '123456'
});
Get a connection from the pool:
pool.getConnection(function(err, connection){
if (err) throw err;
connection.query("SELECT * FROM table", function(err, rows){
if (err) throw err;
console.log(rows);
});
connection.release();
});
Always call connection.release() so the connection returns to the pool.
Complete Example (Original)
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '123456',
database : 'nodedemo'
});
connection.connect();
var queryString = 'SELECT * FROM users';
connection.query(queryString, function(err, rows, fields) {
if (err) {
throw err;
} else {
console.log(rows);
}
});
Sample output:
[
{
"id":1,
"username":"kevin",
"email":"kevin@example.com",
"password":"123456"
},
{
"id":2,
"username":"john",
"email":"john@example.com",
"password":"456789"
}
]
๐ Use Environment Variables (Don't store credentials in code)
Never hardcode DB credentials in your source. Use environment variables with dotenv:
npm install dotenv
Create .env at project root:
DB_HOST=localhost
DB_USER=root
DB_PASS=your_db_password
DB_NAME=nodedemo
Then load it in your app:
require('dotenv').config();
var connection = mysql.createConnection({
host : process.env.DB_HOST,
user : process.env.DB_USER,
password : process.env.DB_PASS,
database : process.env.DB_NAME
});
Keep .env out of version control by adding it to .gitignore.
โ Handle Errors Gracefully
Don’t crash your app with an uncaught error. Use sensible error handling and retries for transient errors:
connection.connect(function(err) {
if (err) {
console.error('DB connection failed:', err);
// implement retry logic or exit
return;
}
console.log('Connected to MySQL');
});
In production, log errors (to file or logging service) and avoid printing sensitive info to the console.
๐ Use Prepared Statements / Parameterized Queries
Avoid string concatenation — use placeholders to prevent SQL injection:
var sql = 'SELECT * FROM users WHERE id = ?';
connection.query(sql, [userId], function(err, rows) {
if (err) throw err;
console.log(rows);
});
Alternatively use connection.escape(userInput) when building strings, but placeholders are preferred.
โ
Modern: Async/Await with mysql2/promise
The mysql package is callback-based. For cleaner async code, use mysql2 which supports Promises:
npm install mysql2
Example using async/await:
const mysql = require('mysql2/promise');
require('dotenv').config();
async function run() {
const conn = await mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME
});
const [rows] = await conn.execute('SELECT * FROM users WHERE id = ?', [1]);
console.log(rows);
await conn.end();
}
run().catch(err => console.error(err));
This style integrates nicely with Express route handlers and modern Node.js codebases.
๐งพ Mini CRUD Example (Using mysql2/promise)
// CREATE, READ, UPDATE, DELETE
const mysql = require('mysql2/promise');
async function crud() {
const db = await mysql.createConnection({ /* ... */ });
// Create
await db.execute('INSERT INTO users (username,email,password) VALUES (?, ?, ?)', ['anna','anna@example.com','pwd']);
// Read
const [users] = await db.execute('SELECT * FROM users');
console.log(users);
// Update
await db.execute('UPDATE users SET email = ? WHERE username = ?', ['anna2@example.com','anna']);
// Delete
await db.execute('DELETE FROM users WHERE username = ?', ['anna']);
await db.end();
}
crud().catch(console.error);
๐ง Performance Tips & Best Practices
- Use connection pooling for web apps (reuse connections, limit concurrent connections).
- Index your columns used in WHERE / JOIN clauses to speed up queries.
- Limit SELECT to only required columns (avoid
SELECT *in production). - Use EXPLAIN to analyze slow queries and optimize them.
- Use transactions (
BEGIN/COMMIT/ROLLBACK) for multi-step updates to keep data consistent. - Avoid long-running DB operations in request handlers — move heavy jobs to background workers if needed.
๐ Pool Example with Promises (mysql2)
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
async function queryUsers() {
const [rows] = await pool.execute('SELECT id, username FROM users LIMIT 10');
return rows;
}
๐ Troubleshooting Common Problems
- Can't connect: check host, port (default 3306), credentials, and firewall.
- Authentication error: verify user privileges and host allowed (e.g.,
'user'@'localhost'vs'user'@'%'). - Too many connections: increase pool size carefully and close/release connections promptly.
- Slow queries: use indexes, avoid N+1 queries, and batch operations when possible.
Next Steps & Libraries to Consider
When your app grows, consider using higher-level libraries/ORMs:
- Sequelize — full-featured ORM with migrations and models.
- Knex.js — SQL query builder (works well with raw SQL and migrations).
- Prisma — modern ORM with type-safety and great DX.
These tools help with maintainability, migrations, and complex queries across environments.
Summary
This post covered the basics of using MySQL with Node.js (installation, connection, queries, pooling), and added practical improvements: secure credential management with environment variables, graceful error handling, parameterized queries to avoid SQL injection, and modern async/await examples with mysql2. For production use prefer connection pooling, promise-based code, and avoid storing secrets in source files.
0 Comments