Maybe you could give him another role (in a scheduled event) with limited access to your application.(Only an edit password form) That way you can show him a form with a message where he can at least see why he is not able to log in...
Edit: As a result of getting several downvotes :) I would like to clearify my answer. In my opinion if someones password is expired, you would like to let the user edit his password and not de-activate him. In order to provide in this operation you could use the solution described above.
Run a scheduled event daily, which sets the 'active' attribute of a system.user to false if expired.
A scheduled event that triggers a microflow that changes the user's password to a different string will effectively stop them logging in. You could then also combine that with microflows to manage them changing their own password periodically, updating the password expire date, some notifications to warn them to change their passwords, etc. etc.
Same issue is also discussed here.