Self-hosted - resetting password without SMTP setup

Hey!

I am running n8n on GCP CloudRun with PostgreSQL. We are having couple of instances served for different needs.
On one of the instances first user registered, thus became an owner. He is the only owner/admin on this instance. He forgot his password and cannot get it back, because we don’t have SMTP configured.

What is the easiest way to reset a password?

Is changing role to global:admin safe (straight in database) and then register a new owner who can generate reset password link?

Hey @rgrzesk, while you wait for a response, here are some things that might help:

Suggested resources

Automatically matched to your question.

Docs:

Forum:

@moosa, @gusgvd, @mechanizedgrowth - you’ve helped with similar issues before, can you take a look?

Automatically suggested by n8n’s community bot. It’s a pilot - please share feedback here.

Hi @rgrzesk

Here is one way to rest users.
This will not delete any other data like workflows or credentials. Just users.

Hi @rgrzesk

Since you are already in the GCP ecosystem, you can use Cloud Shell to connect directly to your Cloud SQL instance and manually update the password hash. This bypasses the need to run n8n locally or manage encryption keys.

  1. Open GCP Cloud Shell from your Google Cloud Console.
  2. Connect to your Cloud SQL instance using the following command:
gcloud sql connect [YOUR_INSTANCE_NAME] --user=postgres
  1. Generate a new bcrypt hash. Since n8n uses bcrypt, you cannot just type a plain-text password. You can use this Python one-liner in your Cloud Shell to generate a hash for your desired password (e.g., NewPassword123!):
python3 -c 'import bcrypt; print(bcrypt.hashpw(b"NewPassword123!", bcrypt.gensalt()).decode())'

Copy the resulting string (it starts with $2b$...).

  1. Run the SQL Update. In the PostgreSQL prompt, run the following command. Note: user is a reserved keyword in PostgreSQL, so it must be wrapped in double quotes.
UPDATE "user" 
SET "password" = '[PASTE_YOUR_HASH_HERE]' 
WHERE "email" = '[OWNER_EMAIL_ADDRESS]';
  1. Verify and Exit:
SELECT email FROM "user" WHERE email = '[OWNER_EMAIL_ADDRESS]';
\q
  1. Login to n8n with the new password.

Hi @rgrzesk Welcome!

Your global:admin plan won’t work — the setup wizard is gated on the settings key userManagement.isInstanceOwnerSetUp = true, not on whether a global:owner row exists, so demoting the owner leaves you with no owner and still no /setup. (global:admin is also an Enterprise-licensed role.)

Since you’re on Postgres, just overwrite that user’s bcrypt hash. One column, nothing else touched, no redeploy:

1. Generate the hash (n8n uses bcryptjs, cost 10):

docker run --rm node:20-alpine sh -c \
  "npm i bcryptjs --silent --prefix /tmp >/dev/null 2>&1 && \
   node -e \"console.log(require('/tmp/node_modules/bcryptjs').hashSync('YourNewPass1',10))\""

Use a password that meets n8n’s rules (8–64 chars, 1 number, 1 uppercase) or you won’t be able to change it in the UI later.

2. Connect and update:

UPDATE "user"
SET password = '$2b$10$...your hash...'
WHERE email = 'owner@yourdomain.com';

Two things that trip people up: user is a reserved word in Postgres and must be double-quoted, and the hash must be in single quotes in your shell or bash will expand $2b/$10 and write garbage.

If that account had MFA on, also SET "mfaEnabled" = false, "mfaSecret" = NULL, "mfaRecoveryCodes" = NULL.

3. Log in from an incognito window — n8n derives part of the auth JWT from the password hash, so old sessions are invalidated and a stale cookie will bounce you. No container restart needed.

Avoid n8n user-management:reset here: you can’t docker exec into Cloud Run, and it wipes all user accounts and returns the instance to the setup wizard. Worth adding SMTP env vars on your Cloud Run services afterwards so this doesn’t recur across the fleet.

Here we use self-hosted on Railway. To manage to resolve it, I included variables directly in the Primary and Worker services. Then I did the deploy and it was resolved.

image

I have tried (on my testing instance) to change other user from global:owner to global:admin and it worked out. After entering the instance I have seen /setup screen again. So the trick works well.
The question is - is that safe? Aren’t those roles saved/used also somewhere else?

That’s what I am planning to do as a solid and long-term solution :slight_smile: At the moment I am just trying to recover the instance quickly without additional deployments.

You’re right, my bad — newer n8n decides whether to show /setup based on whether a global:owner row exists, not the settings key I quoted. Thanks for testing it.

On safety: there are three different role columns, and they’re separate things. user.role is the instance role (the one you changed). project_relation.role and shared_workflow/shared_credentials.role handle project membership and resource ownership — and those are keyed to projectId, not userId. So nothing you did touches who owns which workflow or credential. That part’s fine.

The one thing I’d change: use global:member instead of global:admin. Admin is a Pro/Enterprise account type, so on Community you’ve parked a user in a role the instance can’t license — and the UI tends to grey out unlicensed roles, so you might not be able to change it back without another DB write. Member gets you the same setup screen with none of that.

So: snapshot the DB → set old owner to global:member → register a throwaway owner → Settings → Users → copy password reset link for the old account (works fine without SMTP) → reset → put roles back → delete the temp user. Don’t leave two global:owner rows at once.

Either way, worth getting N8N_EMAIL_MODE=smtp onto all your Cloud Run services — with one owner per instance, this’ll come up again.

Hi @rgrzesk
From n8n 2.17.0 the instance owner can be provisioned from environment variables, which resets the password without touching the database at all. Set these on the Cloud Run service, using the existing owner’s email:

N8N_INSTANCE_OWNER_MANAGED_BY_ENV=true
N8N_INSTANCE_OWNER_EMAIL=owner@yourdomain.com
N8N_INSTANCE_OWNER_FIRST_NAME=Firstname
N8N_INSTANCE_OWNER_LAST_NAME=Lastname
N8N_INSTANCE_OWNER_PASSWORD_HASH=<bcrypt hash>

n8n reapplies these to the existing owner account on every startup, so the revision comes up with the password already changed. While the flag is on, that user is read-only in the UI and API writes for them are rejected, so once you’re in, set N8N_INSTANCE_OWNER_MANAGED_BY_ENV=false, the values it applied stay in place and the UI unlocks again.
It costs one revision, but no role edits and nothing to unwind in the DB afterwards, which is the part that scales across the rest of your instances.