Fixing “NestJS Cannot Connect to MySQL on a VPS: Dev Tools Crash Promptly After Deployment”
You’ve just pushed your NestJS micro‑service to a fresh VPS, watched the logs spin, and—boom—your dev tools (VS Code, Postman, even npm run start:dev) crash the second the app tries to hit MySQL. Panic sets in, you rewrite the whole thing, and the problem repeats. Sound familiar?
Why This Matters
When a production‑grade API can’t reach its database, you’re not just losing code; you’re losing time, money, and credibility. For SaaS founders, agency devs, and freelance engineers, a single connection bug can stall a client launch by days. Fix it once, and you’ll stop chasing “it works on my machine” ghosts forever.
Step‑by‑Step Tutorial
-
Confirm MySQL Is Running & Accessible
Log into your VPS and run:
systemctl status mysqlIf the service isn’t active, start it:
sudo systemctl start mysqlNext, test the network path from your NestJS process:
nc -zv 127.0.0.1 3306 # or if MySQL is on another host nc -zv mysql.example.com 3306 -
Check Environment Variables
Most connection crashes stem from missing or malformed env vars. In
.env(or your Docker secrets), you should have:DB_HOST=127.0.0.1 DB_PORT=3306 DB_USER=nest_user DB_PASSWORD=SuperSecret123! DB_NAME=nest_dbTip: Never store plain passwords in a public repo. Usedotenv-clior a secret manager likeVault. -
Update NestJS TypeORM Config
Open
src/app.module.ts(or a dedicatedtypeorm.config.ts) and confirm the credentials match the .env file:import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule, ConfigService } from '@nestjs/config'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (config: ConfigService) => ({ type: 'mysql', host: config.get('DB_HOST'), port: +config.get('DB_PORT'), username: config.get('DB_USER'), password: config.get('DB_PASSWORD'), database: config.get('DB_NAME'), autoLoadEntities: true, synchronize: false, }), }), // other modules … ], }) export class AppModule {} -
Adjust MySQL Permissions
Even if the credentials are correct, MySQL may reject remote connections. Log into MySQL and run:
CREATE USER 'nest_user'@'%' IDENTIFIED BY 'SuperSecret123!'; GRANT ALL PRIVILEGES ON nest_db.* TO 'nest_user'@'%'; FLUSH PRIVILEGES;If your app runs on the same server, replace
'%'with'localhost'for tighter security. -
Disable Strict SSL (If Needed)
Some VPS setups enable
require_secure_transportMySQL option. If you’re not using SSL, addssl: falsein the TypeORM config:ssl: false,Warning: Turning off SSL on a public server is risky. Use it only for internal testing or secure the connection with a proper certificate. -
Rebuild & Restart
Clear the previous build artifacts, then reinstall and start fresh:
npm run build npm install npm run start:prodWatch the console for a successful
Connected to MySQLmessage. -
Verify with a Simple Query
Create a quick endpoint to prove the connection works:
@Get('ping') async ping(): Promise<string> { const rows = await this.connection.query('SELECT NOW() AS now'); return `DB time is ${rows[0].now}`; }Hit
/pingwith Postman or curl. If you receive the current DB timestamp, you’re golden.
Real‑World Use Case: SaaS Billing Service
A small SaaS built a NestJS billing API that stored invoices in MySQL. After migrating from a local dev box to a DigitalOcean droplet, the API crashed whenever the first payment webhook arrived. By following the steps above, the team:
- Identified a missing
DB_HOSTvariable (it pointed tolocalhostwhile MySQL lived on a separate container). - Granted the correct network permissions (Docker bridge needed
--network host). - Switched from
synchronize: trueto migrations, preventing schema drift.
The result? Zero downtime during the next release and a 40% faster onboarding for new customers.
Results / Outcome
After applying the checklist, developers typically see:
- Immediate elimination of the “cannot connect to MySQL” error.
- Stable dev‑tool experience—no more crashes when the API boots.
- Clear separation between environment config and code, making future deployments painless.
Bonus Tips
- Use a health‑check endpoint. Add
/healththat runs a lightweightSELECT 1query so load balancers know your DB is reachable. - Log connection errors. Wrap TypeORM init in a try/catch and send the stack trace to a monitoring service (e.g., Sentry).
- Employ a connection pool. The default pool size (10) works for most VPS sizes, but you can tweak
extra: { connectionLimit: 20 }for high‑traffic apps. - Automate DB backups. Set up
mysqldumpcron jobs and store snapshots in an S3 bucket.
Monetization Corner (Optional)
If you’re building a product around NestJS + MySQL, consider these quick revenue streams:
- Premium setup scripts. Package the entire checklist as a one‑click installer for $29.
- Managed DB monitoring. Offer a $15/mo service that watches connection health and auto‑restarts failed services.
- Consulting hours. Charge $150/hr for custom migrations or security hardening.
Bottom line: A solid connection setup saves you hours of debugging and opens the door to scaling your API—and your income.
No comments:
Post a Comment