Cómo crear un currículum en inglés efectivo para postularte como Software Engineer (Go, Python, TS y más)

Imagen
Si eres desarrollador y quieres postularte a empresas internacionales o remotas , tu currículum en inglés es tu primera línea de código: si tiene errores, el "programa" ni siquiera compila. Reclutadores técnicos dedican en promedio 6 a 10 segundos a la primera lectura de un CV, así que cada palabra debe justificar su lugar en la página. En este artículo te muestro, paso a paso, cómo armar un currículum en inglés pensado específicamente para roles de Software Engineer con stacks como Go, Python y TypeScript. 1. Elige el formato correcto Antes de escribir una sola línea, define la estructura: Una sola página si tienes menos de 8-10 años de experiencia. Los reclutadores técnicos rara vez leen la segunda página. Formato ATS-friendly : sin tablas, columnas complejas ni gráficos. Muchas empresas usan sistemas de Applicant Tracking System (ATS) que "leen" tu CV antes que un humano; si el diseño es muy creativo, el sistema puede descartarlo por error. Fuente simple...

Cómo solucionar MySQL Error 1045: Access Denied for User (guía definitiva 2026)

Son las 2 de la mañana. Tu deploy funcionaba hace cinco minutos. Cambiaste una variable de entorno, reiniciaste el contenedor, y ahora tu aplicación —o tu terminal, o tu script de Python— te devuelve esto:

ERROR 1045 (28000): Access denied for user 'app_user'@'localhost' (using password: YES)

Si llegaste aquí googleando ese mensaje exacto, no estás solo: es uno de los errores más reportados en foros de MySQL, WordPress, Docker y stacks de Python/Flask. La buena noticia es que, aunque el mensaje suena genérico, las causas reales son solo cuatro o cinco, y casi siempre se resuelven en menos de diez minutos si sabes por dónde empezar.

En este artículo vamos a diagnosticar tu caso específico —no solo "probá cambiar la contraseña"— y a resolverlo con los comandos exactos, incluyendo el conflicto de autenticación que MySQL 8 introdujo y que sigue rompiendo proyectos en 2026.

Qué significa realmente el error 1045

Antes de tocar nada, lee el mensaje completo. Trae más información de la que parece:

ERROR 1045 (28000): Access denied for user 'app_user'@'192.168.1.50' (using password: YES)

Tres datos clave:

  • 'app_user'@'192.168.1.50': es la combinación exacta de usuario y host que MySQL intentó autenticar. MySQL no valida solo el nombre de usuario: valida el par usuario + origen de la conexión. Un usuario creado como 'app_user'@'localhost' no puede conectarse desde 127.0.0.1, desde un contenedor Docker, ni desde una IP remota, aunque la contraseña sea correcta.
  • (using password: YES): te dice si el cliente envió una contraseña. Si ves NO, el problema es que tu aplicación no está enviando ninguna, generalmente por una variable de entorno vacía o mal leída.
  • (28000): es el SQLSTATE estándar para errores de autorización, común a MySQL, MariaDB y otros motores compatibles.

En resumen: <cite index="2-1">MySQL rechazó la conexión porque la combinación de usuario, host y contraseña no coincidió con ninguna entrada autorizada en la tabla mysql.user</cite>. Dicho de otro modo, el error 1045 siempre se reduce a una de estas cinco causas: <cite index="1-1">una contraseña incorrecta, una cuenta de usuario inexistente, un problema de privilegios, un desajuste de host, o un conflicto del plugin de autenticación en MySQL 8.0</cite>.

Vamos a revisar cada una, en el orden en que conviene descartarlas.

Paso 1: Confirma que el usuario existe (y en qué host)

Conéctate como root o con un usuario administrativo y corre:

SELECT User, Host, plugin FROM mysql.user WHERE User = 'app_user';

<cite index="1-1">Si no se devuelve ninguna fila, el usuario no existe</cite> para ese nombre, sin importar cuántas veces hayas escrito bien la contraseña. Si aparece pero con un Host distinto al que estás usando para conectarte, ahí está tu problema: MySQL trata 'app_user'@'localhost', 'app_user'@'127.0.0.1' y 'app_user'@'%' como cuentas completamente distintas.

Si el usuario no existe, créalo:

CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'ContraseñaSegura!';
GRANT ALL PRIVILEGES ON tu_base_de_datos.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;

Si necesitas acceso desde cualquier host (por ejemplo, porque tu app corre en un contenedor Docker con IP dinámica), usa el comodín %, pero con cuidado en producción:

CREATE USER 'app_user'@'%' IDENTIFIED BY 'ContraseñaSegura!';
GRANT ALL PRIVILEGES ON tu_base_de_datos.* TO 'app_user'@'%';
FLUSH PRIVILEGES;

Truco de diagnóstico rápido: si conectarte con -h 127.0.0.1 funciona pero -h localhost falla (o viceversa), el problema no es la contraseña: es que estás forzando una conexión TCP cuando el usuario solo tiene permiso vía socket Unix, o al revés.

Paso 2: Verifica el conflicto de autenticación de MySQL 8

Esta es, hoy en día, la causa más frecuente en proyectos nuevos —y la que menos gente relaciona con el error 1045 a simple vista. <cite index="1-1">MySQL 8.0 cambió el plugin de autenticación por defecto de mysql_native_password a caching_sha2_password</cite>. El problema: <cite index="3-1">muchos clientes antiguos no soportan el nuevo plugin</cite>, lo que genera un 1045 aunque la contraseña sea correcta, porque el handshake de autenticación falla antes de siquiera comparar credenciales.

Verifica qué plugin usa tu usuario:

SELECT User, Host, plugin FROM mysql.user WHERE User = 'app_user';

Si ves caching_sha2_password y tu cliente es antiguo (PyMySQL desactualizado, un driver PHP viejo, o una librería mysqlclient sin compilar contra OpenSSL reciente), tienes dos rutas:

Opción recomendada: actualiza tu librería cliente. En Python, por ejemplo:

pip install --upgrade pymysql mysqlclient

Opción de compatibilidad temporal: cambia el usuario al plugin legado.

ALTER USER 'app_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'ContraseñaSegura!';
FLUSH PRIVILEGES;

Ojo con este detalle si usas MySQL 8.4 o más reciente: <cite index="4-1">el plugin mysql_native_password está incluido pero deshabilitado por defecto, y ese mismo comando ALTER USER falla con el error 1524 indicando que el plugin no está cargado</cite>. Para habilitarlo hay que reiniciar el servidor con la opción correspondiente activada en el archivo de configuración de mysqld.

Paso 3: Revisa si un usuario anónimo te está robando la conexión

Esta causa es menos conocida pero explica muchos casos de "estoy seguro de que la contraseña es correcta y aun así falla". <cite index="4-1">Cuando dos filas de cuentas podrían coincidir con una conexión, MySQL prioriza primero el valor de Host más específico y luego el de User más específico</cite>. Esto significa que una fila anónima ''@'localhost' puede ganarle a tu cuenta 'app_user'@'%' cuando te conectás desde el host local, porque localhost es más específico que %. MySQL intenta autenticarte contra esa cuenta anónima (normalmente con contraseña vacía), falla, y te devuelve el 1045 sin que tu contraseña real llegue a evaluarse.

Para descartarlo:

SELECT User, Host FROM mysql.user WHERE User = '';

Si aparecen filas, elimínalas (a menos que las uses deliberadamente):

DROP USER ''@'localhost';

Paso 4: Diagnóstico específico para Docker

Si tu error aparece solo al conectar desde un contenedor, el motivo casi siempre es el mismo: <cite index="6-1">si creaste 'myuser'@'localhost' pero te conectas desde un contenedor Docker, en realidad te estás conectando desde la IP del contenedor, no desde localhost</cite>. Docker asigna IPs internas (normalmente en el rango 172.17.0.0/16 por defecto), así que tu usuario necesita permiso para ese host o rango, no para localhost.

Solución rápida en docker-compose.yml + SQL:

CREATE USER 'app_user'@'%' IDENTIFIED BY 'ContraseñaSegura!';
GRANT ALL PRIVILEGES ON tu_base_de_datos.* TO 'app_user'@'%';
FLUSH PRIVILEGES;

Y en tu conexión desde Python (usando el nombre del servicio de MySQL definido en docker-compose.yml, no localhost):

import pymysql
import os

try:
    connection = pymysql.connect(
        host=os.environ.get('DB_HOST', 'mysql'),  # nombre del servicio, no localhost
        port=int(os.environ.get('DB_PORT', 3306)),
        user=os.environ['DB_USER'],
        password=os.environ['DB_PASSWORD'],
        database=os.environ['DB_NAME'],
        connect_timeout=10,
    )
    print("Conexión exitosa")
except pymysql.err.OperationalError as e:
    error_code = e.args[0]
    if error_code == 1045:
        print("Acceso denegado: revisa usuario, contraseña y host")
    elif error_code == 1049:
        print("La base de datos no existe")
    else:
        print(f"Error de conexión: {e}")

Paso 5: Si perdiste el acceso de root

Cuando ni siquiera el usuario root funciona, necesitas el modo de recuperación:

sudo systemctl stop mysql
sudo mysqld_safe --skip-grant-tables &
mysql -u root

Dentro de la sesión:

FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'NuevaContraseñaSegura!';
FLUSH PRIVILEGES;

Y para volver a producción:

sudo kill $(sudo cat /var/run/mysqld/mysqld.pid)
sudo systemctl start mysql

Importante: durante el modo --skip-grant-tables, MySQL no valida ninguna contraseña. No dejes el servidor así ni un segundo más de lo necesario, y nunca lo hagas en un servidor expuesto a internet.

El contraargumento: ¿deberías usar % como host?

Es tentador resolver todo con 'usuario'@'%' para no volver a pensar en el tema. No lo hagas por defecto. <cite index="1-1">La recomendación de buenas prácticas es usar usuarios de base de datos separados por aplicación, nunca conectar aplicaciones web con la cuenta root, y crear un usuario dedicado con los privilegios mínimos necesarios para cada aplicación</cite>. Además, <cite index="1-1">se recomienda restringir el acceso remoto solo a IPs específicas</cite> cuando sea posible, en vez de abrir la puerta a cualquier host.

El comodín % es razonable en desarrollo local o dentro de una red Docker interna que no está expuesta a internet. En producción, si tu arquitectura lo permite, es mejor listar hosts o rangos específicos.

Resumen práctico según tu perfil

  • Si sos vibe coder o estás prototipando rápido: lo más probable es que te falte crear el usuario o que estés usando localhost en vez del nombre del servicio Docker. Empieza por el Paso 1 y el Paso 4.
  • Si mantenés un proyecto en producción con MySQL 8: revisa primero el plugin de autenticación (Paso 2). Es la causa que más sorprende porque "la contraseña es correcta" y aun así falla.
  • Si administrás infraestructura o Debian/Ubuntu en servidores propios: además de los pasos anteriores, corré siempre FLUSH PRIVILEGES después de editar mysql.user manualmente con UPDATE en vez de ALTER USER o GRANT —de lo contrario MySQL no relee los cambios hasta el próximo reinicio o flush.
💡 Nota: "Si este tipo de error te persigue seguido, probablemente el problema no es tu código sino tu hosting. Yo migré a Hostinger y no he vuelto a pelear con configuraciones de MySQL rotas." 

El error 1045 parece intimidante por lo genérico del mensaje, pero en la práctica es uno de los errores de MySQL más fáciles de diagnosticar con el método correcto: usuario, host, contraseña, plugin, y privilegios, en ese orden. La próxima vez que te aparezca a las 2am, ya sabés por dónde empezar.

¿Te trabó algo que no está en esta lista? Contame en los comentarios tu mensaje de error exacto y lo agregamos a la guía.

Comentarios

Entradas populares de este blog

El vibe coding: ¿el fin de los programadores o el inicio de una nueva era?

El USB-C de la IA: cómo MCP pasó de protocolo de Anthropic a infraestructura de toda la industria en 16 meses