Auth0's lazy migration changes on 20 January 2027, and half-imported users won't fix themselves
Auth0 is retiring Legacy Custom DB User Import. From 20 January 2027, custom database connections that import users create a full profile during a password reset or a blocked first login. Users already stuck halfway stay stuck, so test the new behaviour now and clean up the old records.
part 34 of 37 · Platform releases, explained from scratchthe ideaA reset or a blocked first login now creates the full profile straight away.
after reading, you can- Spot the users who got stuck halfway, and see why Auth0's Users list and API never showed them
- Test the new import behaviour in a dev tenant with the Dashboard toggle before Auth0 forces it
- Clean up the users already stuck halfway, because the January change won't fix them
If your Auth0 tenant still pulls users across from an old database as they log in, the way that import finishes is about to change. Auth0 retires Legacy Custom DB User Import on 20 January 2027. Turn the new behaviour on in a test tenant first, and clean up the users who are already stuck halfway, because the change won't touch them.
Half-finished moves into Auth0 now finish on the spot, login or no login
Lots of companies move to Auth0 without forcing everyone to reset a password. Auth0 checks each person's password against the old database the first time they sign in, then copies them over. Sometimes that first visit doesn't end in a login. Someone resets a password and wanders off, or Auth0 blocks the login because the password showed up in a breach. Until now, those people could end up half-copied: their details were in Auth0, but nobody could see them in the admin screens. From 20 January Auth0 finishes the copy at that moment instead. People already caught halfway stay that way, so somebody has to fix them by hand.
Think of a building switching tenants to new keys. Your old key gets checked at the door and a new one is cut for you. Turn back before you walk in, and the new key used to sit in a drawer with no name on the list. From January, reception writes your name down the moment the key's cut.
- Auth0 tenant admins
- Developers who own custom DB scripts
- CIAM product owners
- Support teams handling login tickets
- Security teams running breach checks
- Business owners mid-migration
Why a quiet behaviour change still needs a test
This one is short notice by Auth0's own standard. Its migration process page says it tries to give at least six months between announcing an end of life and enforcing it. Here it's about three, and the holidays sit in the middle. If your change freeze starts in mid-December, you've really got about five weeks to test.
Nothing breaks for people who log in normally. The risk is in the edges, and in what you've built around them. A user who clicks a reset link now gets a full Auth0 profile on the spot, built from whatever your Get User scriptdefinitionYour script that asks the old database whether a person exists and what's on their record. Auth0 runs it at sign-up, password changes and logins. From January its answer can become the stored profile, so sloppy output sticks. returns. Reports, exports and sync jobs that read users through the Management API will start counting people who've never logged in to Auth0. Those people used to be invisible.
Then there's the backlog. Auth0 says profiles already stuck in a partial importdefinitionA half-finished migration. Auth0 has stored the user's data and password, but there's no normal user profile, so the person doesn't appear in the Dashboard or the Management API. stay stuck, even when the person goes through the same flow again. One developer on Auth0's community forum described what a stuck record can look like from the outside: a reset flow where the user lookup comes back empty, but creating the user fails with "The user already exists." Auth0's migration guide reads that as a record that's in its internal store but not in your tenant.
-
01 Asks for a reset
Auth0 runs your Get User script against the old database. It finds them, so the reset email goes out.
-
02 Clicks the link
Here's the change. Auth0 builds the full profile as soon as the link's clicked, from Get User data, and the old password doesn't come across.
-
03 Finishes the reset, or doesn't
Under the legacy import, someone who finished the reset and then never logged in could leave a hidden partial record. Now they're already a normal user, and you'll see them in the Dashboard.
-
04 Comes back later
If they closed the tab before setting a password, their next login goes to Auth0's own store, which holds no password for them yet. That's our reading of Auth0's pages, so plan on another reset.
-
05 Resets and signs in
They finish the reset and the new password is saved in Auth0. From then on the old database has nothing to do with how they log in.
Step four is our reading, so test it before you rely on it. Auth0's migration guide says the Login script only runs for users who aren't in the Auth0 store yet. The deprecation notice says a reset imports the user without their old password. Put the two together and someone who abandons a reset can't log in with the old password any more. Auth0 doesn't say this in so many words, so try it in a dev tenant and write down what you see.
What changes, and what stays exactly as it is
The change at a glance
A first-time user gets a standard profile during the reset or blocked-login flow itself. Before, the import only completed after a successful login.
Opening the reset link now imports the user from whatever Get User returns. Their old password stays behind, so they only get a working password by finishing the reset.
Breached password detection blocking a first login used to leave a partial import. Now the user is fully imported. As we read the blocking rules, they still can't log in until they change the password.
Users caught by these flows appear in the Dashboard and come back from the Management API user endpoints. Before, they did neither.
Auth0 lists a migration toggle called Legacy Custom DB User Import. Tenants that qualify can switch early, so you can test it in a quiet week you pick.
Tenants created by 12 October 2026 keep the legacy import until 20 January 2027. After that, Auth0 enforces the new one for anyone who hasn't switched.
Profiles already stuck halfway stay that way, even if the person runs the same flow again. You clean these up yourself.
| Situation | Legacy import | From 20 January 2027 |
|---|---|---|
| First login succeeds | Imported with the same ID and password | No change |
| Reset completed, but the user never logs in with the new password | Partial import, hidden from Dashboard and API | Already a full profile, imported from Get User data when the reset link was opened |
| First login blocked by breached password detection | Partial import | Full profile. Blocking should still demand a password change (our reading) |
| Network failure cuts a first login short | Could leave a partial import | Auth0's notice doesn't describe the new outcome |
| User already in a partial state | Stuck | Still stuck. Clean up by hand |
| Tenant created after 12 October 2026 | Not offered | New behaviour already applies, as we read the notice |
The table carries most of it, but one row deserves a second look. Auth0 lists network failures that interrupt a login as one cause of partial imports, then only describes the new outcome for the reset and breach cases. So don't assume every way of ending up half-imported goes away in January. Keep watching for duplicate-user errors after the switch, too.
The Auth0 dates on the same page
- 12 Oct 2026Legacy Custom DB User Import deprecated
Tenants created by this date keep the old behaviour until the deadline, unless they switch early.
- 7 Nov 2026Today: about ten weeks left
Enough time for a test tenant and a cleanup, provided someone owns it before the holidays.
- 20 Jan 2027End of life for the legacy import
Any tenant that hasn't switched gets the new behaviour automatically. Auth0 doesn't list a way to stay on the old one.
- 4 Mar 2027Uncapped user profile data ends
Auth0 brings in a 50KB profile limit. A Get User script that returns bulky metadata now feeds full profiles, so check sizes.
- 30 Apr 2027Hooks stop running
Hooks are already read-only. If you still have any, plan that move alongside this one.
- 31 Jan 2028Rules stop running
The last of the old extensibility goes. Plan both moves to Actions alongside this one.
- A user is only imported after a successful login
- Abandoned resets can leave hidden partial records
- First logins blocked by a breach check can end up half-imported too
- The Users list misses people who started moving but never finished
- DUPLICATED_USER errors turn up later, with no obvious cause
- Reset and breach-block flows import the user straight away
- Get User data becomes the stored profile
- Users list and API counts now include people who've never logged in
- Someone who walks away from a reset still ends up a real user, just without a password
- Old partial records still need a manual fix
Pick your route before Auth0 picks the date for you
You can do nothing. Auth0 flips every remaining tenant on 20 January regardless, so what you give up is choosing when the problems show up. The table lays out the routes we'd weigh. For most teams, switching early is the right call.
| Route | What you do | Effort | Main risk |
|---|---|---|---|
| Switch early with the toggle | Turn on the new behaviour in dev, then staging, then production, on dates you pick | Low to medium: mostly testing and checking scripts | Little, if Get User returns clean, consistent profiles |
| Wait for Auth0 to enforce it | Change nothing and let 20 January happen | None up front | You find problems in production, possibly during a freeze |
| Finish the migration first | Move the rest of the users across, check counts, then turn the scripts into no-ops | Medium to high, depending on how many users are left | Mixing methods can cause DUPLICATED_USER errors, which Auth0 warns about |
The third route only makes sense when most users have already moved. Auth0's guide says to confirm every user from the old store is in Auth0 before disconnecting. Then you change the Login and Get User scripts to return nothing, and leave Import Users to Auth0definitionThe switch on a custom database connection that turns lazy migration on. With it on, Auth0 copies each user into its own store after a successful login. switched on. One developer on Auth0's forum hit a related trap in a different setup. Accounts created while the connection ran in passthrough mode, before a bulk import, couldn't log in once the old database was cut off.
# example: removes one stuck user, so they can log in and migrate again # needs a Management API token with delete:users CONN_ID="con_XXXXXXXXXXXX" EMAIL="[email protected]" curl -s -X DELETE \ -H "Authorization: Bearer $MGMT_TOKEN" \ "https://$TENANT.auth0.com/api/v2/connections/$CONN_ID/users?email=$EMAIL" # afterwards the user logs in or resets, and the import starts over
That call is Auth0's Delete a connection user endpoint, one of the fixes its migration guide gives for DUPLICATED_USER errors. It works by email, one user at a time, and only on database connections. Run it in a dev tenant first. Make sure the person really is stuck, because deleting a working user throws away their Auth0 data. URL-encode the email if it contains a plus sign, and check each response code before you move to the next user.
What to do before 20 January
Who does what
- Ask whether any Auth0 connection still has Import Users to Auth0 on and talks to an old database.
- Name one person who owns the switch date. Without that, the change happens on Auth0's date, mid-freeze.
- Ask support how many login tickets mention a reset that didn't work. That's your baseline.
- List every custom database connection and note which have Import Users to Auth0 switched on.
- Look for the Legacy Custom DB User Import toggle in the Dashboard. Check your tenant can use it before you plan around it.
- Search tenant logs for DUPLICATED_USER and "user already exists" errors over the last few months.
- Check whether breached password detection blocks logins on these connections. That's one of the two paths that changes.
- Make Get User return the same profile shape and the same user_id as Login. Compare them for real accounts.
- Give both scripts timeouts and clear error messages, as Auth0's best-practice page asks. A hung call to the old database shouldn't look like a wrong password.
- Test in a dev tenant: reset and walk away, a breach-blocked first login, then a normal first login.
- Check what downstream code does with users who have no password yet and haven't logged in.
- Write the support reply before the switch, for users whose old password may stop working after an abandoned reset. Test that case in dev, because someone will call on day one.
- Keep breached password detection on. Auth0's notice changes how the import finishes, and nothing in it turns the blocking off.
- Watch tenant logs for a week after the switch, and compare duplicate-user errors with your baseline.
The order we'd run it in
- 01Find the connections
List custom database connections with import turned on. Any connection that only authenticates against the old database, with import off, isn't what Auth0's notice describes.
- 02Count the stuck users
Search tenant logs and the old database for people who started a reset or a login but aren't in Auth0's Users list. Real-time logs show console.log output from your scripts, which helps.
- 03Fix the scripts
Get User now writes the profile, so give it the full set of fields and the same stable user_id that Login returns. Keep metadata small with the 50KB profile limit coming in March.
- 04Flip the toggle in dev
Run the three test cases: reset and walk away, breach-blocked first login, normal first login. Check each user in the Dashboard and through GET /api/v2/users.
- 05Clean up old partials
For each stuck user, Auth0's guide says delete the connection user, then have them log in or change their password to migrate again. Deletion can't be undone, so work in small batches and record each email and response first.
- 06Switch production on your date
Pick a quiet week before your freeze, tell support, and watch logs for the next few days. Don't leave it for Auth0's date in January.
Harden the migration so the next change hurts less
Before: half-imported users disappear
A first visit that doesn't end in a login can leave data inside Auth0 that neither the Dashboard nor the API will show you.
After: every started import becomes a real user
Reset and breach-block flows create a standard profile from Get User data. Your scripts and logs decide how clean that profile is.
Durable fixes
- 01Put the old database behind a narrow API
Auth0 recommends a protected API with a few endpoints, such as read user and change password, over exposing the database itself. Use an IP allowlist of Auth0's outbound addresses only as one layer, since those addresses are shared across tenants.
- 02Mark users as migrated at the source
Auth0 suggests flagging each user in the old store as migrated. That stops someone you deleted in Auth0 being quietly imported again the next time they try to log in.
- 03Delete from the old store as a separate job
Auth0 advises against deleting users inside the Login script, because an error halfway through can lose the account. Run deletion as its own process once counts match.
- 04Backfill missing metadata with an Action
An interrupted login or reset can leave a user without their user_metadata or app_metadata. Auth0's fix is an Action that spots the gap and fetches the data from the old store.
- 05Set a date to finish
Lazy migration never ends for people who don't come back. Decide when the rest get a bulk move or a forced reset, so the old database can finally be retired.
If it goes wrong
When logins or resets fail after the switch
Most problems here are a support surge or a script bug, not an attack. Treat it as a security incident only if accounts appear that nobody asked for, or a reset goes through for the wrong person.
- 01Confirm the causefirst hour
- Read tenant logs for the failing users. A DUPLICATED_USER error and a wrong password need different fixes.
- Look the user up in the Dashboard. If they're there with no password, they probably walked away from a reset.
- Open Real-time logs and replay one case to see what Get User and Login returned.
- 02Keep people workingsame day
- Send anyone who walked away from a reset a fresh link. As we read Auth0's notice, finishing it is what gives them an Auth0 password, so don't make them wait.
- Give support a two-line explanation they can repeat. Without one, users will assume their account's been wiped.
- Auth0's notice doesn't say whether the early toggle can be turned back off. Find out in dev, before you need it.
- 03Fix the recordsfirst week
- Delete each stuck user's connection record by email, then ask them to log in or reset again. The import starts over from scratch.
- Correct any profiles built from bad Get User data, and fix the script so it doesn't happen again.
- Backfill missing metadata with an Action that reads the old store.
- 04If something looks hostileimmediately
- Reset the affected users' passwords, end their sessions, and check what they accessed.
- Check the old database and its API for unexpected calls. The scripts hold credentials to it.
- Rotate the secrets your custom database scripts use, and involve legal if customer data was exposed.
- 05Learn from itafter
- Add the three test cases to your regression suite for any change to the scripts.
- Set a finish date for the migration, so you aren't running two user stores at the next deprecation.
Four illustrative situations
- the setup
- A consumer subscription service moved to Auth0 a year ago with import on. Most active users have moved. Thousands of dormant ones still only exist in the old database.
- what happens
- After the switch, the next marketing email sends dormant users to reset their passwords. Each click creates a full Auth0 profile, so the user count jumps and the analytics team asks why.
- what to do
- Tell analytics and finance before you switch. Decide whether a profile created by a reset click counts as a migrated user in your reports.
- the setup
- A distributor's partner portal blocks logins that use breached passwords. Some partner users haven't logged in since the migration started, and their passwords turn up in old breaches.
- what happens
- Under the legacy behaviour, a blocked first login could leave them half-imported and stuck with DUPLICATED_USER errors. After the switch they're imported straight away, then asked to change the password.
- what to do
- Keep detection on. Check that the reset email and the support script make sense to someone who was just told their password was in a breach.
- the setup
- A retailer's Get User script was written quickly years ago. It returns only the email and builds user_id from the email address, while Login uses the database key.
- what happens
- Once the reset path imports from Get User, these users get profiles with no metadata and an ID that doesn't match Login. That's the setup for duplicate users later.
- what to do
- Fix the script before the toggle goes on. Return the same fields and the same user_id from both scripts, and test five real accounts.
- the setup
- A software company has moved nearly all its active users and wants the old database gone next quarter. Some users hit broken resets last year and never came back.
- what happens
- Those users sit in a partial state. The January change won't repair them, and once the scripts become no-ops they can't migrate at all.
- what to do
- Find and clear the stuck users first, check counts against the old store, and only then change the scripts to return nothing. Leave Import Users to Auth0 on.
How Cohash helps
We plan and run Auth0 migrations, including custom database connections. For this change that means reviewing your Login and Get User scripts, running the test cases in a dev tenant, and clearing stuck users before you switch. If you've still got Rules or Hooks to move, read our post on the Auth0 Rules and Hooks deadlines too. See our Auth0 page for how we work, or book an assessment if you'd like us to look at your tenant.
What to take from this
- 01
Auth0 retires Legacy Custom DB User Import on 20 January 2027. After that, someone who clicks a reset link or gets breach-blocked on a first login is imported right away, even if they never log in.
- 02
Users already stuck in a partial import stay stuck. Find them and clear them with Delete a connection user, then let them migrate again.
- 03
Whatever Get User returns becomes the stored profile, so make it match Login and use the same stable user_id.
- 04
Switch early with the Dashboard toggle in a dev tenant, then production, before your holiday freeze.
- 05
Expect user counts to rise. As we read Auth0's pages, some abandoned-reset users will need a fresh reset too, so brief support and analytics first.
01What is Auth0 Legacy Custom DB User Import?
It's the old way Auth0 finished lazy migration on custom database connections with Import Users to Auth0 switched on. A user was only fully imported after a successful login, so abandoned resets and breach-blocked first logins could leave partial records. Auth0 deprecated it on 12 October 2026 and ends it on 20 January 2027.
02Do I have to do anything before 20 January 2027?
Auth0 switches remaining tenants automatically, so you don't have to act for the switch itself to happen. You should still test the new behaviour with the Dashboard toggle, check your Get User script, and clean up users already stuck in a partial import, because the change won't fix them.
03Does this affect custom database connections with import turned off?
Auth0's notice only describes connections configured to Import Users to Auth0. If a connection just authenticates against your own database and never imports, it isn't the setup the notice talks about. Check each connection's settings rather than assuming.
04We already have users stuck halfway. What happens to them?
They stay stuck. Auth0 says the new behaviour won't touch them, even if they reset or log in again. Its migration guide's fix for duplicate-user errors is to delete the user with the Management API, using Delete a User or Delete a connection user. Then they log in or change their password and migrate again.
05Will users have to reset their passwords?
Users whose first login succeeds won't notice anything. Someone who clicks a reset link gets imported without the old password, so as we read Auth0's pages they'll need to finish a reset to log in. Test that path in a dev tenant.
06How do I switch to the new behaviour early?
Auth0 lists a Dashboard migration toggle called Legacy Custom DB User Import for tenants that qualify. Turn it on in a development tenant first, run your test cases, then switch production on a date you choose.
07Our Auth0 user count went up after the change. Why?
People who click a reset link or are blocked on a first login now get a standard profile straight away. Before, someone who finished a reset but never logged in, or was breach-blocked, could become a hidden partial record. Reports that count users through the Dashboard or Management API will include them.
Three questions, about a minute
Pick an answer and we'll tell you if it's right, and why it is or isn't. The score stays in this browser.
-
Q1Someone who's only in your old database clicks a reset link and then closes the tab. What's in Auth0 after 20 January 2027?
show the answer
B. A full profile from Get User data, but their old password doesn't come with it Under the new behaviour the import completes when the reset link is opened, using whatever Get User returns. The old password isn't brought across, so the user has a real profile but no Auth0 password yet.
-
Q2Your tenant has hundreds of users stuck in a partial import from last year. What does the January change do for them?
show the answer
D. Nothing. They stay partial until someone on your team cleans them up Auth0 is clear that the new behaviour only applies to first-time users. Existing partial records stay partial, even if the person runs the same flow again, so you have to delete and re-migrate them yourself.
-
Q3Your Get User script builds user_id from the email, but Login uses the database key. Why does that matter more after the switch?
show the answer
A. Get User now writes the stored profile during resets, so mismatched IDs create duplicate users Resets now import users from Get User data. If its ID differs from the one Login returns, the same person can end up as two users. Auth0 asks for the same stable user_id from both scripts.