shell calls sys.__interactivehook__
diff --git a/CHANGES.rst b/CHANGES.rst
index 8c615d5fb8..2657dae910 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -70,6 +70,8 @@ Unreleased
 -   Support async views, error handlers, before and after request, and
     teardown functions. :pr:`3412`
 -   Support nesting blueprints. :issue:`593, 1548`, :pr:`3923`
+-   ``flask shell`` sets up tab and history completion like the default
+    ``python`` shell if ``readline`` is installed. :issue:`3941`
 
 
 Version 1.1.2
diff --git a/src/flask/cli.py b/src/flask/cli.py
index c7b8813508..a5971d6065 100644
--- a/src/flask/cli.py
+++ b/src/flask/cli.py
@@ -887,6 +887,24 @@ def shell_command():
 
     ctx.update(app.make_shell_context())
 
+    # Site, customize, or startup script can set a hook to call when
+    # entering interactive mode. The default one sets up readline with
+    # tab and history completion.
+    interactive_hook = getattr(sys, "__interactivehook__", None)
+
+    if interactive_hook is not None:
+        try:
+            import readline
+            from rlcompleter import Completer
+        except ImportError:
+            pass
+        else:
+            # rlcompleter uses __main__.__dict__ by default, which is
+            # flask.__main__. Use the shell context instead.
+            readline.set_completer(Completer(ctx).complete)
+
+        interactive_hook()
+
     code.interact(banner=banner, local=ctx)
 
 

This will set up readline tab and history completion by default.

<!--
Link to relevant issues or previous PRs, one per line. Use "fixes" to
automatically close an issue.
-->

- fixes #3941

<!--
Ensure each step in CONTRIBUTING.rst is complete by adding an "x" to
each box below.

If only docs were changed, these aren't relevant and can be removed.
-->

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [x] Add or update relevant docs, in the docs folder and in code.
- [x] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [x] Add `.. versionchanged::` entries in any relevant code docs.
- [x] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.
