For reference I’ve just been scratching my head over a similar problem (see screenshot).
I ran bench migrate by accident and it failed halfway through. I set maintenance_mode to zero and no change.

It turns out the patch handler also blocks access in the database while doing a migration, but doesn’t clear it until the migration finishes.
You can test with:
bench console
import frappe
Set using:
frappe.modules.patch_handler.block_user(True)
Clear using:
frappe.modules.patch_handler.block_user(False)
To check the database to see if it is set:
bench mariadb
select defkey,defvalue from `tabDefaultValue` where parent like '__global' and defkey like '__session_status%';
When set:
+--------------------------+--------------------------------------------------------------------------------------------------------------+
| defkey | defvalue |
+--------------------------+--------------------------------------------------------------------------------------------------------------+
| __session_status | stop |
| __session_status_message | Patches are being executed in the system. Please try again in a few moments. |
+--------------------------+--------------------------------------------------------------------------------------------------------------+
HTH!