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

Een MySQL-database gebruiken met een discord.py-bot (aiomysql)

Discord-bothostingUpdated Nov 6, 20267 min read

Kort antwoord. Voeg aiomysql toe aan je discord.py-bot, maak één pool aan in setup_hook met autocommit=True en laat elke query erdoorheen lopen met %s-plaatsaanduidingen. Zonder autocommit=True (of een commit() na elke schrijfactie) slaat aiomysql je INSERTs niet op. 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.py 2.7.1, aiomysql 0.3.2 en Python 3.12, tegen MariaDB 10.11 met een databaseaccount dat is ingesteld zoals het onze (20 verbindingen, querylimiet van 120 seconden): de start, de tabel en het commando /warn, 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 Python (aiomysql) 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. Je code leest de waarden met os.environ, dus het wachtwoord staat nooit in de bestanden van je bot. Meer over dit paneel: Omgevingsvariabelen en geheimen instellen voor je Discord-bot.

3. De code

requirements.txt

discord.py
aiomysql

bot.py

import os

import aiomysql
import discord
from discord import app_commands


class Bot(discord.Client):
    def __init__(self):
        super().__init__(intents=discord.Intents.default())
        self.tree = app_commands.CommandTree(self)
        self.pool = None

    async def setup_hook(self):
        # One pool for the whole bot. The values come from the Environment pane.
        self.pool = await aiomysql.create_pool(
            host=os.environ["DB_HOST"],
            port=int(os.environ["DB_PORT"]),
            user=os.environ["DB_USER"],
            password=os.environ["DB_PASSWORD"],
            db=os.environ["DB_NAME"],
            autocommit=True,
            maxsize=5,
        )
        async with self.pool.acquire() as conn:
            async with conn.cursor() as cur:
                await cur.execute(
                    "CREATE TABLE IF NOT EXISTS warnings ("
                    "id INT AUTO_INCREMENT PRIMARY KEY, "
                    "guild_id BIGINT UNSIGNED NOT NULL, "
                    "user_id BIGINT UNSIGNED NOT NULL, "
                    "reason VARCHAR(200) NOT NULL, "
                    "created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
                    "KEY guild_user (guild_id, user_id))"
                )
        print("Database ready")
        await self.tree.sync()

    async def close(self):
        if self.pool is not None:
            self.pool.close()
            await self.pool.wait_closed()
        await super().close()


bot = Bot()


@bot.tree.command(description="Warn a member and count their warnings")
@app_commands.guild_only()
@app_commands.describe(user="Who to warn", reason="Why")
async def warn(interaction: discord.Interaction, user: discord.Member, reason: app_commands.Range[str, 1, 200]):
    async with bot.pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute(
                "INSERT INTO warnings (guild_id, user_id, reason) VALUES (%s, %s, %s)",
                (interaction.guild_id, user.id, reason),
            )
            await cur.execute(
                "SELECT COUNT(*) FROM warnings WHERE guild_id = %s AND user_id = %s",
                (interaction.guild_id, user.id),
            )
            (total,) = await cur.fetchone()
    await interaction.response.send_message(f"{user.mention} has {total} warning(s).")


@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")


bot.run(os.environ["DISCORD_TOKEN"])

Wat het doet: discord.py voert setup_hook één keer uit, tijdens het inloggen en voordat er een event binnenkomt, zodat de pool en de tabel warnings bestaan voordat het eerste commando binnenkomt. Daarna registreert het /warn bij Discord. @app_commands.guild_only() houdt het commando uit privéberichten, waar geen server is om iets voor op te slaan. Discord-ID's passen in BIGINT UNSIGNED. De %s-plaatsaanduidingen worden door de driver ingevuld, zodat een reden zoals '); DROP TABLE warnings; -- als gewone tekst wordt opgeslagen. Bouw de SQL nooit op met een f-string.

4. Starten

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

De autocommit-valkuil

aiomysql opent verbindingen met autocommit uit. Een INSERT blijft dan in een open transactie staan. Als de verbinding met die nog open transactie terug naar de pool gaat, sluit aiomysql hem, en MariaDB gooit de niet-bevestigde rij weg. In onze test werd een rij die was ingevoegd op een pool zonder autocommit=True door 0 andere verbindingen gezien. Geef autocommit=True mee aan create_pool, zoals hierboven, of roep await conn.commit() aan na je schrijfacties.

Limieten die ertoe doen voor je pool

  • 20 gelijktijdige verbindingen per databasegebruiker. Elk proces dat dezelfde login gebruikt telt mee. Verbinding 21 wordt geweigerd met (1226, "User '...' has exceeded the 'max_user_connections' resource (current value: 20)"). maxsize=5 houdt de bot ruim eronder.
  • 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 fouten die aiomysql gaf in onze test (ze komen van PyMySQL, dat aiomysql eronder gebruikt):

  • pymysql.err.OperationalError (1045, "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.
  • pymysql.err.OperationalError (2003, "Can't connect to MySQL server on ..."): verkeerde host of poort, of een verbinding van buiten PlayNHost. De database accepteert alleen verbindingen van PlayNHost-servers en phpMyAdmin, dus dit krijg je ook op je eigen computer.
  • (1226, ... 'max_user_connections' ...): te veel open verbindingen, zie de limieten hierboven.

Een variabele die ontbreekt in Omgeving stopt de bot voordat hij verbindt, met KeyError: 'DB_HOST' of de naam van de ontbrekende, omdat de code elke waarde leest met os.environ[...]. Voeg hem toe en start de bot opnieuw: variabelen gelden vanaf de volgende start.

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

Hoeveel geheugen het toevoegt

Het installeren van discord.py en aiomysql met pip vanaf nul piekte in onze test op 78 MB geheugen, in een container met een limiet van 512 MB zoals ons kleinste botabonnement. Hoeveel de draaiende bot nodig heeft, hangt vooral af van op hoeveel servers hij zit: Hoeveel RAM heeft een Discord-bot nodig?

Hetzelfde in JavaScript, 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