NOUVEAU 📢 Offre de lancement limitée : jusqu'à 70 % de remise sur votre premier mois, pour tous les jeux !Voir les offres

Comment utiliser une base de données MySQL avec un bot discord.js (mysql2)

Hébergement de bots DiscordUpdated Nov 6, 20269 min read

Réponse courte. Ajoutez mysql2 à votre bot discord.js, créez un seul pool de connexions à partir des variables d’environnement au démarrage du bot, et faites passer chaque requête par lui avec des marqueurs ?. Chez PlayNHost, chaque offre de bot inclut une base de données MySQL : créez-la sur la page Bases de données, collez ses informations dans le volet Environnement, et le code ci-dessous fonctionne tel quel. La base de données accepte les connexions de vos serveurs PlayNHost et de phpMyAdmin, pas celles de votre propre ordinateur. Nous avons testé ce code le 6 novembre 2026 avec discord.js 14.28.1, mysql2 3.24.6 et Node.js 22, sur MariaDB 10.11 avec un compte de base de données configuré comme le nôtre (20 connexions, limite de requête de 120 secondes) : le démarrage, la table et le gestionnaire de /warn, mais pas une vraie connexion à Discord.

Ce qu’il vous faut

1. Créer la base de données

  1. Ouvrez votre serveur de bot dans le panel et cliquez sur Bases de données.
  2. Cliquez sur Nouvelle base de données. Le Libellé est facultatif ; Sera créée sous le nom affiche le nom complet. Cliquez sur Créer une base de données.
  3. La page de la nouvelle base s’ouvre (plus tard, cliquez dessus dans Vos bases de données). Sa carte Connexion affiche Hôte, Port, Base de données, Nom d’utilisateur et Mot de passe. Sous Config prête à l’emploi, Config pour propose un extrait Node.js (mysql2) avec les mêmes valeurs déjà remplies.

2. Enregistrer les identifiants dans Environnement

  1. Ouvrez la page Bot, le volet Environnement, et cliquez sur Coller un fichier .env.
  2. Collez ces cinq lignes avec les valeurs de la carte Connexion :
    DB_HOST=your-host
    DB_PORT=3306
    DB_NAME=your-database
    DB_USER=your-username
    DB_PASSWORD=your-password
  3. DB_PASSWORD reçoit un badge Secret : il est enregistré en écriture seule et n’est plus jamais affiché. Cliquez sur Importer 5 variables.

Utilisez le vrai port de la carte Connexion. Garder le mot de passe hors de votre code l’empêche de se retrouver dans un fichier ou dans un dépôt Git. Plus de détails sur ce volet : Comment définir des variables d’environnement et des secrets pour votre bot Discord.

3. Le 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);
});

Ce qu’il fait : au démarrage, le bot crée la table warnings si elle manque, affiche Database ready, puis se connecte. /warn enregistre un avertissement et répond avec le total du membre. discord.js fournit les ID Discord sous forme de chaînes, car ils sont trop grands pour un nombre JavaScript, ils sont donc stockés comme du texte. Les marqueurs ? envoient le texte du membre à la base séparément du SQL, si bien qu’un motif comme '); DROP TABLE warnings; -- est enregistré comme du texte brut.

Deux lignes gardent le bot en vie. setContexts(InteractionContextType.Guild) et la vérification !interaction.guildId bloquent /warn en message privé, où il n’y a aucun serveur pour enregistrer l’avertissement. Le try/catch répond par un court message privé quand une requête échoue. Sans lui, discord.js transmet l’erreur à son événement error, et si personne n’écoute, Node.js arrête le bot. Dans notre test, nous avons supprimé la table et lancé /warn : le bot a journalisé ER_NO_SUCH_TABLE, a répondu Could not save the warning. Try again later. et a continué à tourner.

4. Lancer le bot

  1. Envoyez index.js et package.json dans Fichiers. N’envoyez pas node_modules.
  2. Appuyez sur Démarrer et ouvrez Console. Le démarrage installe les paquets, puis affiche [PlayNHost] Starting your bot, Database ready et Logged in as ....
  3. Dans Discord, tapez /warn. Pour voir les lignes, ouvrez la page de la base et cliquez sur Ouvrir dans phpMyAdmin.

Les limites qui comptent pour votre pool

  • 20 connexions simultanées par utilisateur de base de données. Tout processus qui utilise le même identifiant compte : votre bot, une deuxième copie, un tableau de bord. La connexion 21 est refusée avec ER_USER_LIMIT_REACHED. Dans notre test, un pool avec connectionLimit: 30 a échoué avec cette erreur dès que 30 requêtes ont tourné en même temps. Un pool de 5 n’ouvre jamais plus de 5 connexions : les requêtes en trop attendent une connexion libre.
  • Une requête qui dure plus de 120 secondes est interrompue. MariaDB y met fin avec l’erreur 1969, Query execution was interrupted (max_statement_time exceeded). Dans notre test, cela est arrivé après 120.03 secondes. Les requêtes d’un bot prennent normalement des millisecondes, donc cela ne touche qu’une requête qui s’emballe.
  • 500 MB par base de données. La page Bases de données indique l’espace utilisé. À 500 MB, les écritures sont bloquées jusqu’à ce que vous supprimiez des lignes.
  • Les sauvegardes du serveur n’incluent pas la base de données. Exportez-la de temps en temps depuis phpMyAdmin.

Les erreurs et leur signification

Voici les messages exacts que mysql2 a donnés dans notre test :

  • ER_ACCESS_DENIED_ERROR ... Access denied for user : DB_USER ou DB_PASSWORD incorrect. Après Réinitialiser le mot de passe sur la carte Connexion, l’ancien mot de passe cesse de fonctionner immédiatement : remplacez DB_PASSWORD et redémarrez le bot.
  • ECONNREFUSED : rien n’a accepté la connexion à cet hôte et ce port. Vérifiez DB_HOST et DB_PORT. Un DB_HOST manquant aboutit aussi ici, car mysql2 se connecte alors à localhost, où aucune base ne tourne : la variable manque dans Environnement, ou le bot n’a pas été redémarré après son ajout.
  • ENOTFOUND : DB_HOST est mal orthographié, donc le nom n’existe pas.
  • ETIMEDOUT : rien n’a répondu en 10 secondes, l’attente par défaut de mysql2. Quel que soit le message, une connexion depuis votre propre ordinateur échoue : la base de données n’accepte que les connexions des serveurs PlayNHost et de phpMyAdmin.
  • ER_USER_LIMIT_REACHED ... has exceeded the 'max_user_connections' resource (current value: 20) : trop de connexions ouvertes, voir les limites ci-dessus. En général, une nouvelle connexion par commande qui n’est jamais fermée, ou une deuxième copie du bot.

Plus d’erreurs de bot : Erreurs courantes des bots Discord et leur signification.

Combien de mémoire cela ajoute

Installer discord.js et mysql2 de zéro a atteint un pic de 147 MB de mémoire (cache de fichiers non compté) dans notre test, dans un conteneur limité à 512 MB comme notre plus petite offre de bot. Du démarrage jusqu’au refus de notre jeton de test par Discord, le bot a utilisé 31 MB au maximum ; il avait créé la table mais ne s’était jamais connecté. Un bot connecté et présent sur de nombreux serveurs en utilise davantage : De combien de RAM un bot Discord a-t-il besoin ?

La même chose en Python, ou avec Prisma

Besoin d’un serveur de bot avec une base de données incluse ? Voir les offres de bots.

Votre bot est hébergé ailleurs ? Transférez-le chez nous

NOS DERNIERS ARTICLES