Python – Conexión a base de datos MariaDB

Para hablar con MariaDB desde Python hay dos opciones buenas: el conector oficial, mariadb, y PyMySQL, escrito en Python puro. El código es casi el mismo; cambia cómo se instalan y cómo se marcan los parámetros.

Instalarlo

pip install mariadb

Y aquí está la primera sorpresa. En Linux, si falta la biblioteca de C de MariaDB, la instalación falla con esto:

salida/bin/sh: 1: mariadb_config: not found
error: subprocess-exited-with-error

El conector oficial es una extensión en C y necesita compilarse contra MariaDB Connector/C. En Debian y Ubuntu se resuelve con sudo apt install libmariadb-dev gcc antes del pip install. Si prefieres no compilar nada, pip install pymysql funciona sin más.

La versión anterior de esta página usaba mysql.connector, el conector de MySQL, renombrado como mariadb en el import. Funciona, porque MariaDB es compatible con MySQL en el protocolo, pero confunde: parecía el conector de MariaDB y no lo era.

Conectar y crear una tabla

import mariadb

conexion = mariadb.connect(host="localhost", port=3306, user="app",
                           password="clave", database="pruebas")
cur = conexion.cursor()
cur.execute("SELECT VERSION()")
print("conectado a MariaDB", cur.fetchone()[0])

cur.execute("""
    CREATE TABLE usuarios (
        id     INT AUTO_INCREMENT PRIMARY KEY,
        correo VARCHAR(100) NOT NULL UNIQUE,
        nombre VARCHAR(100)
    )""")
salidaconectado a MariaDB 11.8.9-MariaDB-ubu2404
No te conectes como root, como hacía el ejemplo anterior. Crea un usuario para la aplicación con permiso solo sobre su base de datos. Si alguien consigue colarse por tu programa, con root tiene el servidor entero; con un usuario limitado, solo esa base.

Insertar y consultar, con parámetros

cur.executemany("INSERT INTO usuarios (correo, nombre) VALUES (?, ?)",
                [("ana@ejemplo.com", "Ana Pérez"), ("luis@ejemplo.com", "Luis Gómez")])
conexion.commit()
print("insertados:", cur.rowcount)

cur.execute("SELECT id, correo, nombre FROM usuarios WHERE nombre LIKE ?", ("%Pérez%",))
for fila in cur:
    print("  ", fila)
salidainsertados: 2
   (1, 'ana@ejemplo.com', 'Ana Pérez')

Los valores van con ? en la consulta y aparte, en una tupla. Fíjate en la coma de ("%Pérez%",): sin ella no es una tupla, es solo un texto entre paréntesis. Y sin commit() los cambios no se guardan; al cerrar la conexión, se pierden.

Un duplicado

try:
    cur.execute("INSERT INTO usuarios (correo, nombre) VALUES (?, ?)", ("ana@ejemplo.com", "Otra Ana"))
    conexion.commit()
except mariadb.IntegrityError as e:
    conexion.rollback()
    print("IntegrityError:", e)
salidaIntegrityError: Duplicate entry 'ana@ejemplo.com' for key 'correo'

Por qué parámetros y no f-strings

malicioso = "x' OR '1'='1"

cur.execute("SELECT COUNT(*) FROM usuarios WHERE correo = ?", (malicioso,))
print("con parámetros, el ataque devuelve:", cur.fetchone()[0])

cur.execute(f"SELECT COUNT(*) FROM usuarios WHERE correo = '{malicioso}'")
print("pegando la cadena, devuelve:       ", cur.fetchone()[0])
salidacon parámetros, el ataque devuelve: 0
pegando la cadena, devuelve:        2
Ahí está la diferencia, en dos números. El mismo texto, pasado como parámetro, se busca tal cual y no encuentra nada. Pegado dentro de la consulta deja de ser un dato y pasa a ser SQL: la condición se convierte en OR '1'='1', que siempre se cumple, y devuelve todas las filas. Con un DELETE el resultado sería el que te imaginas. Nunca se monta una consulta con f-strings ni con +, aunque el dato «venga de dentro».

Con PyMySQL

import pymysql

with pymysql.connect(host="localhost", user="app", password="clave", database="pruebas") as c:
    with c.cursor() as cur:
        cur.execute("SELECT COUNT(*) FROM usuarios WHERE nombre LIKE %s", ("%Gómez%",))
        print(cur.fetchone()[0])
salida1

Lo mismo, con una diferencia que despista: PyMySQL marca los parámetros con %s, no con ?. Parece formato de cadenas, pero no lo es: siguen yendo aparte y el controlador los escapa.

Más información en inglés: Connect to MariaDB in Python.

Todo el código se ejecutó con Python 3.14 en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.

3 comentarios en «Python – Conexión a base de datos MariaDB»

  1. Hola buenas, he probado a hacer lo que usted dice con mi propia base de datos, y me aparece el siguiente error:

    Traceback (most recent call last):
    File «/home/pi/.local/lib/python3.5/site-packages/mysql/connector/network.py», line 509, in open_connection
    self.sock.connect(sockaddr)
    ConnectionRefusedError: [Errno 111] Connection refused

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
    File «/home/pi/Desktop/pysql2.py», line 3, in
    mariadb_conexion = mariadb.connect(host=’localhost’,port=’3306′,user=’ja’,password=’rootroot’,database=’usuarios’)
    File «/home/pi/.local/lib/python3.5/site-packages/mysql/connector/__init__.py», line 179, in connect
    return MySQLConnection(*args, **kwargs)
    File «/home/pi/.local/lib/python3.5/site-packages/mysql/connector/connection.py», line 95, in __init__
    self.connect(**kwargs)
    File «/home/pi/.local/lib/python3.5/site-packages/mysql/connector/abstracts.py», line 716, in connect
    self._open_connection()
    File «/home/pi/.local/lib/python3.5/site-packages/mysql/connector/connection.py», line 206, in _open_connection
    self._socket.open_connection()
    File «/home/pi/.local/lib/python3.5/site-packages/mysql/connector/network.py», line 512, in open_connection
    errno=2003, values=(self.get_address(), _strioerror(err)))
    mysql.connector.errors.InterfaceError: 2003: Can’t connect to MySQL server on ‘localhost:3306’ (111 Connection refused)

    Alguna solucion?
    Gracias

    Responder
    • Hola, el error parece más un problema de conexión, puertos o permisos para acceder a la base de datos que de código. Revisa los permisos de conexión de tu usuario en MySQL.

      Responder
      • dice conexion rechazada, el problema de donde esta alojada la base de datos que por defecto no acepta conexiones de fuera, tienes que buscar solucion por ese lado, el codigo este va perfecto

        Responder

Deja un comentario