ERROR 1062: Duplicate entry

El error 1062 es uno de los más frecuentes en MySQL y aparece cuando intentas guardar un valor que ya existe en una columna que no admite repetidos. MySQL lo lanza para proteger la integridad de los datos: si una columna tiene una clave primaria o un índice UNIQUE, el servidor se niega a aceptar una segunda fila con el mismo valor, ya sea en un INSERT, en un UPDATE o al crear un índice nuevo sobre una tabla que ya tiene datos.

La buena noticia es que el propio mensaje contiene casi toda la información necesaria para resolverlo: el valor que está duplicado y el nombre del índice que ha saltado. En este artículo verás cómo leer ese mensaje, cuáles son las causas más habituales (algunas bastante menos obvias de lo que parece) y qué opciones tienes para solucionarlo según lo que quieras conseguir.

El mensaje de error

Cuando se produce, MySQL devuelve un mensaje con el código 1062, el estado SQL 23000 (el estado estándar para violaciones de restricciones de integridad) y dos datos entre comillas:

ERROR 1062 (23000): Duplicate entry 'ana.garcia@email.com' for key 'clientes.email'

El primer valor, 'ana.garcia@email.com', es el dato que ya existe en la tabla. El segundo, 'clientes.email', es el nombre del índice que impide el duplicado. En MySQL 8 el nombre del índice va precedido por el nombre de la tabla, mientras que en MySQL 5.7 solo aparece el nombre del índice (for key 'email'). Si la restricción es la clave primaria, el índice se llama PRIMARY:

ERROR 1062 (23000): Duplicate entry '1500' for key 'pedidos.PRIMARY'

Cuando el índice abarca varias columnas, MySQL muestra los valores unidos por un guion. Por ejemplo, en una tabla de líneas de pedido con un índice único sobre el pedido y el producto, el mensaje sería Duplicate entry '1500-37' for key 'pedido_lineas.uk_pedido_producto', lo que indica que el producto 37 ya está en el pedido 1500.

Cómo identificar el índice que provoca el error

Si el nombre del índice no te dice nada, porque lo generó MySQL automáticamente o porque la tabla la diseñó otra persona, puedes consultar la definición completa de la tabla. SHOW CREATE TABLE muestra todas las claves con sus columnas:

SHOW CREATE TABLE clientes;
CREATE TABLE `clientes` (
  `id` int NOT NULL AUTO_INCREMENT,
  `nombre` varchar(100) NOT NULL,
  `email` varchar(150) NOT NULL,
  `nif` char(9) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
  UNIQUE KEY `uk_nif` (`nif`)
) ENGINE=InnoDB AUTO_INCREMENT=2481 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

Otra opción es SHOW INDEX, que devuelve una fila por cada columna de cada índice. La columna Non_unique vale 0 en los índices que no admiten duplicados, así que es fácil filtrar los que te interesan:

SHOW INDEX FROM clientes WHERE Non_unique = 0;

Con esto ya sabes qué columnas están implicadas, y el siguiente paso es entender por qué el valor está repetido.

Causas más habituales

Aunque todas las variantes de este error se reducen a lo mismo (un valor repetido donde no se permite), el origen puede ser muy distinto. Conviene revisar estas causas en orden, porque las primeras son las más comunes.

Un duplicado real en una columna UNIQUE

El caso más sencillo es que el dato realmente ya exista. Un cliente que intenta registrarse dos veces con el mismo email o un producto que se da de alta con un sku ya asignado a otro producto provocan este error, y en realidad MySQL está haciendo exactamente lo que debe:

INSERT INTO productos (sku, nombre, precio)
VALUES ('CAM-0042', 'Camiseta básica azul', 14.95);
ERROR 1062 (23000): Duplicate entry 'CAM-0042' for key 'productos.sku'

Aquí la solución no es técnica sino de negocio: decidir si hay que rechazar el alta, actualizar el producto existente o asignar otro código. Si quieres repasar cómo funcionan estas restricciones, el artículo sobre la restricción UNIQUE lo explica en detalle.

Clave primaria duplicada al insertar un id explícito

Otra causa muy frecuente es insertar filas indicando el valor de la clave primaria a mano, por ejemplo al copiar datos de otra base de datos o al restaurar registros borrados. Si ese id ya está ocupado, el error menciona PRIMARY:

INSERT INTO pedidos (id, cliente_id, fecha, total)
VALUES (1500, 87, '2026-09-14', 129.90);
ERROR 1062 (23000): Duplicate entry '1500' for key 'pedidos.PRIMARY'

Esto ocurre mucho al fusionar dos bases de datos que numeraron sus filas de forma independiente: ambas tienen un pedido 1500 y no pueden convivir en la misma tabla. En estos casos lo correcto suele ser no enviar el id y dejar que AUTO_INCREMENT asigne uno nuevo, ajustando después las referencias en las tablas relacionadas. Puedes ver más sobre este tema en el artículo sobre PRIMARY KEY.

Contador AUTO_INCREMENT y ids generados por la aplicación

InnoDB mantiene un contador para cada columna AUTO_INCREMENT y lo ajusta automáticamente cuando insertas un id explícito mayor que el valor actual. Por eso es raro que el contador por sí solo genere duplicados. Lo que sí es habitual es que la aplicación calcule los ids por su cuenta con algo como SELECT MAX(id) + 1: si dos peticiones hacen ese cálculo a la vez, ambas obtienen el mismo número y la segunda en insertar recibe el error 1062.

Si sospechas que el contador no está donde debería, puedes consultarlo con SHOW CREATE TABLE (aparece como AUTO_INCREMENT=2481 al final de la definición) y moverlo con ALTER TABLE:

ALTER TABLE pedidos AUTO_INCREMENT = 5000;

Ten en cuenta que InnoDB no permite colocar el contador por debajo del id más alto que existe en la tabla: si pides un valor menor, lo ajusta al máximo más uno. La solución de fondo, en cualquier caso, es dejar que MySQL genere los ids con AUTO_INCREMENT en lugar de calcularlos en el código.

Duplicado en PRIMARY con el valor 0

A veces el valor duplicado que muestra el mensaje es '0'. Esto suele indicar que la clave primaria no tiene AUTO_INCREMENT (algo común en tablas migradas desde otros sistemas) y que la aplicación inserta filas sin indicar el id, de modo que todas reciben el valor 0. Esto pasa cuando la columna se definió con DEFAULT 0 o cuando el servidor funciona sin modo estricto; con el modo estricto activo, que es lo predeterminado en MySQL 8, omitir el id sin valor por defecto daría otro error, el 1364 (Field 'id' doesn't have a default value). La primera fila entra sin problemas y la segunda falla:

ERROR 1062 (23000): Duplicate entry '0' for key 'facturas.PRIMARY'

La solución es añadir AUTO_INCREMENT a la columna, después de corregir la fila con id 0 si ya existe:

ALTER TABLE facturas MODIFY id INT NOT NULL AUTO_INCREMENT;

Duplicados por mayúsculas, acentos y espacios

Este es el caso que más desconcierta, porque los dos valores parecen distintos a simple vista. La collation por defecto de MySQL 8, utf8mb4_0900_ai_ci, no distingue mayúsculas ni acentos, así que para un índice UNIQUE los valores Ana.Garcia@email.com y ana.garcia@email.com son el mismo, igual que José y jose:

INSERT INTO clientes (nombre, email) VALUES ('Ana García', 'ana.garcia@email.com');
INSERT INTO clientes (nombre, email) VALUES ('Ana García', 'Ana.Garcia@email.com');
ERROR 1062 (23000): Duplicate entry 'Ana.Garcia@email.com' for key 'clientes.email'

Con collations más antiguas como utf8mb4_general_ci o utf8mb4_unicode_ci ocurre además otra cosa: son de tipo PAD SPACE, lo que significa que ignoran los espacios al final al comparar. Con ellas, 'CAM-0042' y 'CAM-0042 ' también chocan en el índice. Puedes comprobar el tipo de una collation consultando la columna PAD_ATTRIBUTE de information_schema.COLLATIONS.

En la mayoría de los casos este comportamiento es deseable (no quieres dos cuentas con el mismo email escrito con distintas mayúsculas), así que la solución pasa por normalizar el dato antes de guardarlo, por ejemplo con LOWER(TRIM(email)). Si de verdad necesitas distinguir mayúsculas, puedes cambiar la columna a una collation sensible como utf8mb4_0900_as_cs o utf8mb4_bin.

Al crear un índice UNIQUE sobre datos existentes

El error también aparece fuera de los INSERT. Si añades una restricción UNIQUE a una tabla que ya contiene duplicados, ALTER TABLE falla con el mismo código y te muestra el primer valor repetido que encuentra:

ALTER TABLE clientes ADD UNIQUE KEY uk_telefono (telefono);
ERROR 1062 (23000): Duplicate entry '612345678' for key 'clientes.uk_telefono'

Como solo informa de un valor, lo práctico es buscar todos los duplicados antes de volver a intentarlo, agrupando por la columna y quedándote con los grupos de más de una fila:

SELECT telefono, COUNT(*) AS veces
FROM clientes
GROUP BY telefono
HAVING COUNT(*) > 1
ORDER BY veces DESC;

Una vez localizados, tendrás que decidir cuál conservar en cada caso. Los artículos sobre encontrar registros duplicados y eliminar registros duplicados explican varias técnicas para hacerlo de forma segura.

En un UPDATE que desplaza valores

Un UPDATE también puede provocar el error, incluso cuando el resultado final no tendría duplicados. El ejemplo típico es una columna de posición con índice único, en la que quieres desplazar todas las filas una posición hacia abajo:

UPDATE categorias SET posicion = posicion + 1;
ERROR 1062 (23000): Duplicate entry '2' for key 'categorias.uk_posicion'

MySQL comprueba la restricción fila a fila. Al actualizar la categoría en posición 1, esta pasa a valer 2 mientras la que ya estaba en la posición 2 todavía no se ha movido, y el índice lo rechaza. La solución es procesar las filas en el orden adecuado, empezando por la de mayor posición:

UPDATE categorias SET posicion = posicion + 1 ORDER BY posicion DESC;

Soluciones según lo que necesites

Una vez entendida la causa, la solución depende de qué quieres que ocurra cuando llega un valor repetido: rechazarlo, ignorarlo en silencio o actualizar la fila existente. MySQL ofrece herramientas distintas para cada caso.

Ignorar la fila duplicada con INSERT IGNORE

INSERT IGNORE convierte el error en una advertencia y descarta la fila duplicada, sin detener la sentencia. Es útil en cargas masivas donde sabes que puede haber repetidos y quieres quedarte con los que ya existían:

INSERT IGNORE INTO productos (sku, nombre, precio)
VALUES ('CAM-0042', 'Camiseta básica azul', 14.95),
       ('CAM-0043', 'Camiseta básica roja', 14.95);
 
SHOW WARNINGS;
+---------+------+----------------------------------------------------------+
| Level   | Code | Message                                                  |
+---------+------+----------------------------------------------------------+
| Warning | 1062 | Duplicate entry 'CAM-0042' for key 'productos.sku'       |
+---------+------+----------------------------------------------------------+

Úsalo con cuidado, porque IGNORE no solo silencia los duplicados: también convierte en advertencias otros errores, como valores demasiado largos o fuera de rango, que se guardan truncados o ajustados. Si lo usas, revisa siempre las advertencias con SHOW WARNINGS.

Actualizar la fila existente con ON DUPLICATE KEY UPDATE

Cuando lo que quieres es "insertar si no existe y actualizar si ya existe", la herramienta adecuada es INSERT ... ON DUPLICATE KEY UPDATE. Si la fila choca con una clave única, MySQL ejecuta la parte UPDATE sobre la fila existente en lugar de lanzar el error:

INSERT INTO productos (sku, nombre, precio)
VALUES ('CAM-0042', 'Camiseta básica azul', 12.95) AS nuevo
ON DUPLICATE KEY UPDATE
    nombre = nuevo.nombre,
    precio = nuevo.precio;

La sintaxis con alias (AS nuevo) está disponible desde MySQL 8.0.19 y sustituye a la función VALUES(), que está marcada como obsoleta. El artículo sobre INSERT ON DUPLICATE KEY UPDATE cubre esta sentencia en profundidad.

Por qué REPLACE puede ser peligroso

REPLACE parece una alternativa cómoda porque nunca lanza el error 1062, pero funciona de una forma muy distinta: si encuentra un duplicado, borra la fila existente y después inserta la nueva. Eso tiene consecuencias importantes. La fila recibe un id nuevo si la clave primaria es AUTO_INCREMENT, se ejecutan los triggers de borrado y, lo más grave, si otras tablas tienen claves foráneas con ON DELETE CASCADE apuntando a esa fila, sus registros hijos se borran en cascada. Reemplazar un cliente con REPLACE podría eliminar todos sus pedidos. Salvo que entiendas bien estos efectos, es preferible ON DUPLICATE KEY UPDATE. Tienes más detalles en el artículo sobre REPLACE.

Capturar el error en la aplicación

Muchos desarrolladores intentan evitar el error comprobando primero con un SELECT si el valor existe y solo después insertando. El problema es que entre ambas consultas otra petición puede insertar el mismo valor, así que el error acaba apareciendo igualmente cuando hay tráfico. La forma robusta es intentar el INSERT directamente y capturar el error 1062 (o el estado SQL 23000) para responder de forma adecuada. En PHP con PDO quedaría así:

try {
    $stmt = $pdo->prepare('INSERT INTO clientes (nombre, email) VALUES (?, ?)');
    $stmt->execute([$nombre, $email]);
} catch (PDOException $e) {
    if ($e->errorInfo[1] === 1062) {
        echo 'Ya existe una cuenta con ese email.';
    } else {
        throw $e;
    }
}

En Node.js con mysql2 el error trae errno igual a 1062 y code igual a 'ER_DUP_ENTRY', y en Python con mysql-connector puedes comprobar err.errno == 1062. De esta forma el índice único de la base de datos es la única fuente de verdad y la aplicación solo traduce el error a un mensaje comprensible.

Cómo evitar el error 1062

La mayoría de las apariciones de este error se evitan con unos pocos hábitos. Deja que MySQL genere las claves primarias con AUTO_INCREMENT en lugar de calcularlas en el código. Normaliza los datos que deben ser únicos (emails en minúsculas y sin espacios, códigos en mayúsculas) antes de guardarlos, y ten presente la collation de cada columna para saber qué valores considera iguales MySQL. Antes de añadir un índice UNIQUE a una tabla con datos, busca y resuelve los duplicados. Y en el código, elige conscientemente entre rechazar, ignorar o actualizar: ON DUPLICATE KEY UPDATE para sincronizaciones, INSERT IGNORE solo cuando de verdad quieras descartar filas y la captura del error cuando el usuario deba saber que el dato ya existe.

Resumen

El error 1062 Duplicate entry indica que un INSERT, UPDATE o ALTER TABLE intenta dejar un valor repetido en una clave primaria o un índice UNIQUE. El mensaje muestra el valor y el nombre del índice, que puedes localizar con SHOW CREATE TABLE o SHOW INDEX. Las causas van desde un duplicado real hasta diferencias invisibles de mayúsculas, acentos o espacios, pasando por ids calculados en la aplicación y actualizaciones que desplazan valores. Según lo que necesites, puedes descartar la fila con INSERT IGNORE, actualizar la existente con ON DUPLICATE KEY UPDATE o capturar el error en la aplicación, evitando REPLACE cuando la tabla tenga relaciones con borrado en cascada.

Escrito por Eduardo Lázaro