A Django admin account is wonderfully convenient—and unusually powerful. The command takes less than a minute, but the account it creates can often add, change, and delete nearly every registered object. I treat that first login as a security operation, not as project boilerplate.

The shortest correct path

  1. Confirm the project points at the intended database.

  2. Apply authentication and admin migrations.

  3. Run createsuperuser interactively so the password does not enter shell history.

  4. Start the development server only for local verification.

  5. Open the configured admin URL and test login and logout.

  6. Harden the deployed admin before exposing it to a network.

Prerequisites and tested baseline

These commands follow Django 5.2 LTS. A project generated by startproject normally includes the admin, authentication, content types, sessions, and messages apps plus their middleware. If your settings were customized, verify those dependencies and make sure the admin is connected in the URL configuration.

project/urls.pypython
from django.contrib import admin
from django.urls import path
 
urlpatterns = [
    path("admin/", admin.site.urls),
]

The route exposes the admin site, not an account

  • admin.site.urls connects Django’s admin login and registered model views.

  • Changing admin/ may reduce noise in logs, but it is not a substitute for authentication, HTTPS, and monitoring.

  • The account is stored in the configured database, so confirm environment variables before creating it.

  • Production static files need a proper serving pipeline for the admin CSS and JavaScript.

Apply the database migrations

Django project root containing manage.pybash
python manage.py showmigrations auth admin contenttypes sessions
python manage.py migrate --plan
python manage.py migrate
Planned operations:
...
Applying sessions.0001_initial... OK

Risk level: caution. Review the command before running it.

Why this runs before user creation

  • The auth tables must exist before Django can store the user and permissions.

  • showmigrations displays recorded state; migrate --plan previews pending operations.

  • migrate is caution-level because it mutates the selected database. Review and back up important environments first.

  • Do not use --fake merely to silence an error; it changes migration history without running schema operations.

Create the superuser interactively

Django project rootbash
python manage.py createsuperuser --username alice-admin --email alice@example.com
Password:
Password (again):
Superuser created successfully.

Risk level: caution. Review the command before running it.

The prompt protects more than convenience

  • The password input is hidden and does not become a command-line argument.

  • Django’s user manager hashes the password; the raw value is not stored in the user row.

  • Password validators reject common, short, numeric-only, or user-similar values according to project settings.

  • Do not bypass a validator for a real administrator just to finish setup quickly.

  • The command creates a user with is_staff=True and is_superuser=True; the latter grants all permissions.

  • Replace the example identity with an accountable person or controlled break-glass account.

Start locally and sign in

Django project rootbash
python manage.py runserver 127.0.0.1:8000
Starting development server at http://127.0.0.1:8000/

The development server stays local

  • Open http://127.0.0.1:8000/admin/ and use the identifier and password just created.

  • The built-in server is for development, not a production deployment.

  • Binding to 127.0.0.1 avoids exposing the development server to other machines.

  • After login, only registered models appear; creating an administrator does not automatically register application models.

  • Log out and verify the session ends before considering the check complete.

Verify flags without printing secrets

Django project rootbash
python manage.py shell <<'PY'
from django.contrib.auth import get_user_model

User = get_user_model()
user = User._default_manager.get_by_natural_key("alice-admin")
print({
    "identifier": user.get_username(),
    "active": user.is_active,
    "staff": user.is_staff,
    "superuser": user.is_superuser,
    "usable_password": user.has_usable_password(),
})
PY
{'identifier': 'alice-admin', 'active': True, 'staff': True, 'superuser': True, 'usable_password': True}

These attributes explain admin eligibility

  • get_user_model() respects a swapped user model instead of importing the built-in User.

  • get_by_natural_key() resolves the value through the manager and active login identifier.

  • The default admin permission check requires an active staff user.

  • A superuser receives every permission check, but is_staff is what allows normal admin-site entry.

  • has_usable_password() does not reveal or validate a password; it only reports whether password authentication is possible.

  • Never print password hashes, session cookies, tokens, or secrets in diagnostic output.

Reset a forgotten admin password

Django project rootbash
python manage.py changepassword alice-admin
Changing password for user 'alice-admin'
Password:
Password (again):
Password changed successfully for user 'alice-admin'

Risk level: caution. Review the command before running it.

Reset through Django’s password API

  • changepassword hashes the replacement correctly and applies configured validation.

  • Run it against the same database and settings used by the failing login.

  • Do not update the password column with SQL or assign a raw string to user.password.

  • After a suspected compromise, also investigate sessions, logs, API credentials, and the path by which the secret leaked.

Staff users are usually safer than more superusers

For routine administration, create a normal user, enable is_staff, and grant only the needed model permissions or groups. Staff status permits admin entry; permissions determine which registered models and actions the user may access. Keep a separately controlled superuser for tasks that truly require unrestricted authority.

Non-interactive creation in deployment pipelines

Django supports createsuperuser --noinput and DJANGO_SUPERUSER_PASSWORD plus field-specific environment variables. That mechanism is useful for controlled bootstrap automation, but a plain deployment step can rerun, leak environment values, race across replicas, or create a predictable permanent credential.

  • Prefer a one-time, idempotent management command executed by a controlled release job.

  • Read the bootstrap password from a secret manager and remove or rotate it immediately after first use.

  • Fail safely if the identity already exists instead of silently replacing its password or privileges.

  • Avoid printing environment variables or command tracing around secret handling.

  • For mature systems, provision named staff identities through the organization’s identity lifecycle rather than a shared bootstrap superuser.

Why the admin login fails

  • “No such table” or migration error: point at the intended database and apply the auth/admin/session migrations.

  • Credentials are rejected: verify the active settings, database, login identifier, keyboard layout, and then use changepassword.

  • Correct password but admin denies access: inspect is_active and is_staff; a normal active user without staff status cannot enter.

  • Email entered where username is expected: check the active model’s USERNAME_FIELD and authentication backend.

  • Login works locally but not behind a proxy: inspect HTTPS detection, secure-cookie settings, host configuration, CSRF trusted origins, and proxy headers.

  • Admin page has no styling: build and serve static files correctly; this is separate from authentication.

  • Models are missing after login: register them with the admin and confirm the app is installed.

  • Repeated redirect to login: inspect session cookies, domain/path attributes, middleware, time synchronization, and whether requests reach the same session store.

Production hardening that matters

  • Serve the admin only over HTTPS and configure secure session and CSRF cookies.

  • Run python manage.py check --deploy with production settings and resolve its findings.

  • Set DEBUG=False, a precise ALLOWED_HOSTS, correct trusted origins, HSTS, and proxy SSL handling.

  • Restrict network reachability when practical and add rate limiting at a suitable edge, while not treating it as complete brute-force protection.

  • Use individual accounts, least privilege, strong unique passwords, and multi-factor or upstream identity controls where your architecture supports them.

  • Monitor successful and failed logins, privilege changes, sensitive actions, and unusual access patterns.

  • Keep Django and dependencies supported and patched; test backup restoration and account recovery.

Official Django references