NIEUW 📢 Beperkte lanceeractie: tot 70% korting op je eerste maand, voor elke game!Bekijk pakketten

Een MySQL-database gebruiken met een discord.js-bot (mysql2)

Discord-bothostingUpdated Nov 6, 20268 min read

Kort antwoord. Voeg mysql2 toe aan je discord.js-bot, maak bij het starten van de bot één verbindingspool aan op basis van omgevingsvariabelen en laat elke query erdoorheen lopen met ?-plaatsaanduidingen. Bij PlayNHost bevat elk botabonnement één MySQL-database: maak hem aan op de pagina Databases, plak de gegevens in het paneel Omgeving, en de code hieronder werkt zoals hij is. De database accepteert verbindingen van je PlayNHost-servers en phpMyAdmin, niet van je eigen computer. We hebben deze code getest op 6 november 2026 met discord.js 14.28.1, mysql2 3.24.6 en Node.js 22, tegen MariaDB 10.11 met een databaseaccount dat is ingesteld zoals het onze (20 verbindingen, querylimiet van 120 seconden): de start, de tabel en de /warn-handler, maar geen echte Discord-login.

Wat je nodig hebt

1. De database aanmaken

  1. Open je botserver in het paneel en klik op Databases.
  2. Klik op Nieuwe database. Een Weergavenaam is optioneel; Wordt aangemaakt als toont de volledige naam. Klik op Database aanmaken.
  3. De pagina van de nieuwe database opent (later klik je hem aan onder Jouw databases). Op de kaart Verbinding staan Host, Poort, Database, Gebruikersnaam en Wachtwoord. Onder Kant-en-klare config heeft Config voor een snippet Node.js (mysql2) met dezelfde waarden al ingevuld.

2. De gegevens in Omgeving zetten

  1. Open de pagina Bot, het paneel Omgeving, en klik op Een .env-bestand plakken.
  2. Plak deze vijf regels met de waarden van de kaart Verbinding:
    DB_HOST=your-host
    DB_PORT=3306
    DB_NAME=your-database
    DB_USER=your-username
    DB_PASSWORD=your-password
  3. DB_PASSWORD krijgt een badge Geheim: het wordt alleen-schrijven opgeslagen en nooit meer getoond. Klik op 5 variabelen importeren.

Gebruik de echte poort van de kaart Verbinding. Als je het wachtwoord uit je code houdt, komt het nooit in een bestand of in een Git-repository terecht. Meer over dit paneel: Omgevingsvariabelen en geheimen instellen voor je Discord-bot.

3. De code

package.json

{
  "name": "my-discord-bot",
  "private": true,
  "main": "index.js",
  "dependencies": {
    "discord.js": "^14",
    "mysql2": "^3"
  }
}

index.js

const { Client, Events, GatewayIntentBits, InteractionContextType, MessageFlags, REST, Routes, SlashCommandBuilder } = require('discord.js');
const mysql = require('mysql2/promise');

// One pool for the whole bot. The values come from the Environment pane.
const pool = mysql.createPool({
  host: process.env.DB_HOST,
  port: Number(process.env.DB_PORT),
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  connectionLimit: 5,
});

const commands = [
  new SlashCommandBuilder()
    .setName('warn')
    .setDescription('Warn a member and count their warnings')
    .setContexts(InteractionContextType.Guild)
    .addUserOption((o) => o.setName('user').setDescription('Who to warn').setRequired(true))
    .addStringOption((o) => o.setName('reason').setDescription('Why').setRequired(true).setMaxLength(200))
    .toJSON(),
];

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.once(Events.ClientReady, async () => {
  await new REST().setToken(process.env.DISCORD_TOKEN).put(Routes.applicationCommands(client.user.id), { body: commands });
  console.log(`Logged in as ${client.user.tag}`);
});

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand() || interaction.commandName !== 'warn' || !interaction.guildId) return;
  const user = interaction.options.getUser('user', true);
  const reason = interaction.options.getString('reason', true);
  try {
    await pool.execute('INSERT INTO warnings (guild_id, user_id, reason) VALUES (?, ?, ?)', [interaction.guildId, user.id, reason]);
    const [rows] = await pool.execute('SELECT COUNT(*) AS total FROM warnings WHERE guild_id = ? AND user_id = ?', [interaction.guildId, user.id]);
    await interaction.reply(`${user} has ${rows[0].total} warning(s).`);
  } catch (err) {
    console.error(err);
    if (!interaction.replied) await interaction.reply({ content: 'Could not save the warning. Try again later.', flags: MessageFlags.Ephemeral }).catch(console.error);
  }
});

async function main() {
  await pool.query(`CREATE TABLE IF NOT EXISTS warnings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    guild_id VARCHAR(20) NOT NULL,
    user_id VARCHAR(20) NOT NULL,
    reason VARCHAR(200) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    KEY guild_user (guild_id, user_id)
  )`);
  console.log('Database ready');
  await client.login(process.env.DISCORD_TOKEN);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

Wat het doet: als de bot start, maakt hij de tabel warnings aan als die ontbreekt, toont Database ready en logt dan in. /warn slaat een waarschuwing op en antwoordt met het totaal van het lid. discord.js geeft Discord-ID's als strings, omdat ze te groot zijn voor een JavaScript-getal, dus ze worden als tekst opgeslagen. De ?-plaatsaanduidingen sturen de tekst van het lid los van de SQL naar de database, zodat een reden zoals '); DROP TABLE warnings; -- als gewone tekst wordt opgeslagen.

Twee regels houden de bot in leven. setContexts(InteractionContextType.Guild) en de controle !interaction.guildId voorkomen /warn in een privébericht, waar geen server is om iets voor op te slaan. De try/catch antwoordt met een kort privébericht als een query mislukt. Zonder die blokken geeft discord.js de fout door aan zijn error-event, en als daar niemand luistert, stopt Node.js de bot. In onze test verwijderden we de tabel en voerden we /warn uit: de bot logde ER_NO_SUCH_TABLE, antwoordde Could not save the warning. Try again later. en bleef draaien.

4. Starten

  1. Upload index.js en package.json bij Files. Upload node_modules niet.
  2. Druk op Starten en open Console. Bij het starten worden de pakketten geïnstalleerd, daarna zie je [PlayNHost] Starting your bot, Database ready en Logged in as ....
  3. Typ in Discord /warn. Om de rijen te bekijken, open je de pagina van de database en klik je op Openen in phpMyAdmin.

Limieten die ertoe doen voor je pool

  • 20 gelijktijdige verbindingen per databasegebruiker. Elk proces dat dezelfde login gebruikt telt mee: je bot, een tweede kopie ervan, een dashboard. Verbinding 21 wordt geweigerd met ER_USER_LIMIT_REACHED. In onze test mislukte een pool met connectionLimit: 30 met die fout zodra 30 queries tegelijk liepen. Een pool van 5 opent nooit meer dan 5: extra queries wachten op een vrije verbinding.
  • Een query die langer dan 120 seconden duurt, wordt gestopt. MariaDB beëindigt hem met fout 1969, Query execution was interrupted (max_statement_time exceeded). In onze test gebeurde dat na 120.03 seconden. De queries van een bot duren normaal milliseconden, dus dit raakt alleen een op hol geslagen query.
  • 500 MB per database. De pagina Databases toont hoeveel er gebruikt is. Bij 500 MB worden schrijfacties gestopt tot je rijen verwijdert.
  • Serverback-ups bevatten de database niet. Exporteer hem af en toe vanuit phpMyAdmin.

Fouten en wat ze betekenen

Dit zijn de exacte meldingen die mysql2 gaf in onze test:

  • ER_ACCESS_DENIED_ERROR ... Access denied for user: verkeerde DB_USER of DB_PASSWORD. Na Wachtwoord resetten op de kaart Verbinding werkt het oude wachtwoord meteen niet meer: vervang DB_PASSWORD en start de bot opnieuw.
  • ECONNREFUSED: niets nam de verbinding aan op die host en poort. Controleer DB_HOST en DB_PORT. Ook een ontbrekende DB_HOST eindigt hier, want mysql2 verbindt dan met localhost, waar geen database draait: de variabele ontbreekt in Omgeving, of de bot is na het toevoegen niet opnieuw gestart.
  • ENOTFOUND: DB_HOST is verkeerd gespeld, dus de naam bestaat niet.
  • ETIMEDOUT: niets antwoordde binnen 10 seconden, de standaardwachttijd van mysql2. Welke melding je ook ziet, een verbinding vanaf je eigen computer mislukt: de database accepteert alleen verbindingen van PlayNHost-servers en phpMyAdmin.
  • ER_USER_LIMIT_REACHED ... has exceeded the 'max_user_connections' resource (current value: 20): te veel open verbindingen, zie de limieten hierboven. Meestal een nieuwe verbinding per commando die nooit wordt gesloten, of een tweede kopie van de bot.

Meer botfouten: Veelvoorkomende Discord-botfouten en wat ze betekenen.

Hoeveel geheugen het toevoegt

Het installeren van discord.js en mysql2 vanaf nul piekte in onze test op 147 MB geheugen (bestandscache niet meegeteld), in een container met een limiet van 512 MB zoals ons kleinste botabonnement. Vanaf de start tot Discord ons testtoken weigerde, gebruikte de bot hooguit 31 MB; hij had de tabel aangemaakt maar nooit ingelogd. Een bot die ingelogd is en op veel servers zit, gebruikt meer: Hoeveel RAM heeft een Discord-bot nodig?

Hetzelfde in Python, of met Prisma

Een botserver met database inbegrepen nodig? Bekijk de botabonnementen.

Draait je bot al ergens anders? Verhuis hem naar ons

ONZE NIEUWSTE BLOGS