Fixing the Force Password Change Lockout for SAML2 SSO Users in Moodle
Users created with manual auth and the "Force password change" flag get stuck in a redirect loop when switched to SAML2 SSO — here is the SQL to find them and the fix.
When you switch a Moodle account from manual authentication to SAML2 single sign-on, any user who still has the “Force password change” flag set gets locked out. They cannot log in and cannot self-resolve it. This guide explains why it happens and how to clear it safely, in bulk.
The symptom
A user authenticates successfully through your identity provider, then instead of landing in Moodle they hit an error page:
You cannot proceed without changing your password, however there is no available page for changing it. Please contact your Moodle Administrator.
It is not a redirect loop, and it is not a failed login. SSO works; Moodle then refuses to let the user proceed. This typically appears right after you migrate a set of accounts from manual auth to saml2, or after a bulk user import that set the force-password-change flag.
Why it happens
Moodle stores a per-user preference, auth_forcepasswordchange, set to 1 when an account must change its password at next login. On every login, core checks this flag (lib/moodlelib.php). If it is set, Moodle wants to send the user to the change-password form, but only if the account’s auth method can actually change a password locally:
- For manual accounts, the password is local, so Moodle shows the change-password form. Normal behavior.
- For SAML2 (and other external SSO) accounts, the password is owned by the identity provider, not Moodle. The auth plugin reports that it cannot change passwords, so there is no form to send the user to. Moodle has nowhere to route them, so it stops with the “no available page for changing it” error.
The flag is harmless while the account is manual. It becomes a lockout the moment the account is switched to SSO without the flag being cleared first. So the accounts most affected are exactly those created or imported as manual with “force password change” ticked, then later moved to SAML2.
Finding affected users
The flag lives in mdl_user_preferences. To list SSO users who are currently carrying it:
SELECT up.userid, u.username, u.email
FROM mdl_user_preferences up
JOIN mdl_user u ON u.id = up.userid
WHERE up.name = 'auth_forcepasswordchange'
AND up.value = '1'
AND u.auth = 'saml2';
This is a read-only query and safe to run anywhere. It tells you the scope before you change anything.
Clearing the flag
The correct way to clear it is to delete the preference, which is exactly what Moodle does internally when a password change completes (unset_user_preference('auth_forcepasswordchange', $user) in login/lib.php). Setting the value to 0 also works at read time but leaves a stale row behind; deleting it is the clean equivalent of the core behavior.
Preferred: the Moodle way, per user. For one or a few accounts, edit the user’s profile (Site administration > Users > Browse list of users > select the user > Edit profile) and untick “Force password change”. This goes through Moodle’s API and purges caches correctly.
For a bulk fix, the safest route that still goes through the Moodle API is a short script run via admin/cli, iterating the affected user ids from the query above and calling unset_user_preference('auth_forcepasswordchange', $userid) for each. That clears the preference and invalidates the per-user preference cache the way the UI does.
If you clear it with direct SQL, understand the trade-off. A statement like:
DELETE FROM mdl_user_preferences
WHERE name = 'auth_forcepasswordchange'
AND userid IN (SELECT id FROM mdl_user WHERE auth = 'saml2');
will remove the flag, but it bypasses Moodle’s caching: user preferences are cached, so you must purge caches afterwards (admin/cli/purge_caches.php) or affected users may still hit the stale flag until the cache expires. Direct writes to a production database should always be preceded by a backup and ideally run inside a transaction. The unset_user_preference route avoids all of this, which is why it is preferred over hand-written SQL.
Preventing it on the next migration
When you migrate a batch of accounts to SAML2, clear auth_forcepasswordchange as part of the same migration step, before or alongside the auth switch, so no account ever ends up SSO-authenticated with the flag still set. If you provision accounts from an upstream system (CRM, HR feed) that sets “force password change” by default, turn that off for accounts destined for SSO.
What not to reach for
admin/cli/reset_password.php does not help here: it only operates on manual-auth accounts and only sets a password, so it neither targets your SAML2 users nor clears the force-change flag. The fix is clearing the preference, not resetting a password that the identity provider owns.
Solin implements and troubleshoots Moodle SAML2 SSO integrations.
Contact us