diff --git a/CHANGES.md b/CHANGES.md
index 5b29f20..1fc8c65 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -33,6 +33,8 @@
 
 <!-- Changes to how Black can be configured -->
 
+- Black now uses the presence of debug f-strings to detect target version. (#3215)
+
 ### Documentation
 
 <!-- Major changes to documentation and policies. Small docs changes
diff --git a/src/black/__init__.py b/src/black/__init__.py
index 2a5c750..b8a9d03 100644
--- a/src/black/__init__.py
+++ b/src/black/__init__.py
@@ -87,6 +87,7 @@ from black.output import color_diff, diff, dump_to_file, err, ipynb_diff, out
 from black.parsing import InvalidInput  # noqa F401
 from black.parsing import lib2to3_parse, parse_ast, stringify_ast
 from black.report import Changed, NothingChanged, Report
+from black.trans import iter_fexpr_spans
 from blib2to3.pgen2 import token
 from blib2to3.pytree import Leaf, Node
 
@@ -1240,6 +1241,7 @@ def get_features_used(  # noqa: C901
 
     Currently looking for:
     - f-strings;
+    - self-documenting expressions in f-strings (f"{x=}");
     - underscores in numeric literals;
     - trailing commas after * or ** in function signatures and calls;
     - positional only arguments in function signatures and lambdas;
@@ -1261,6 +1263,11 @@ def get_features_used(  # noqa: C901
             value_head = n.value[:2]
             if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}:
                 features.add(Feature.F_STRINGS)
+                if Feature.DEBUG_F_STRINGS not in features:
+                    for span_beg, span_end in iter_fexpr_spans(n.value):
+                        if n.value[span_beg : span_end - 1].rstrip().endswith("="):
+                            features.add(Feature.DEBUG_F_STRINGS)
+                            break
 
         elif is_number_token(n):
             if "_" in n.value:
diff --git a/src/black/mode.py b/src/black/mode.py
index 32b65d1..f6d0cbf 100644
--- a/src/black/mode.py
+++ b/src/black/mode.py
@@ -49,6 +49,7 @@ class Feature(Enum):
     ANN_ASSIGN_EXTENDED_RHS = 13
     EXCEPT_STAR = 14
     VARIADIC_GENERICS = 15
+    DEBUG_F_STRINGS = 16
     FORCE_OPTIONAL_PARENTHESES = 50
 
     # __future__ flags
@@ -81,6 +82,7 @@ VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
     },
     TargetVersion.PY38: {
         Feature.F_STRINGS,
+        Feature.DEBUG_F_STRINGS,
         Feature.NUMERIC_UNDERSCORES,
         Feature.TRAILING_COMMA_IN_CALL,
         Feature.TRAILING_COMMA_IN_DEF,
@@ -93,6 +95,7 @@ VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
     },
     TargetVersion.PY39: {
         Feature.F_STRINGS,
+        Feature.DEBUG_F_STRINGS,
         Feature.NUMERIC_UNDERSCORES,
         Feature.TRAILING_COMMA_IN_CALL,
         Feature.TRAILING_COMMA_IN_DEF,
@@ -106,6 +109,7 @@ VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
     },
     TargetVersion.PY310: {
         Feature.F_STRINGS,
+        Feature.DEBUG_F_STRINGS,
         Feature.NUMERIC_UNDERSCORES,
         Feature.TRAILING_COMMA_IN_CALL,
         Feature.TRAILING_COMMA_IN_DEF,
@@ -120,6 +124,7 @@ VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
     },
     TargetVersion.PY311: {
         Feature.F_STRINGS,
+        Feature.DEBUG_F_STRINGS,
         Feature.NUMERIC_UNDERSCORES,
         Feature.TRAILING_COMMA_IN_CALL,
         Feature.TRAILING_COMMA_IN_DEF,

diff --git a/tests/test_black.py b/tests/test_black.py
index bb7784d..81e7a9a 100644
--- a/tests/test_black.py
+++ b/tests/test_black.py
@@ -310,6 +310,26 @@ class BlackTestCase(BlackBaseTestCase):
         versions = black.detect_target_versions(root)
         self.assertIn(black.TargetVersion.PY38, versions)
 
+    def test_detect_debug_f_strings(self) -> None:
+        root = black.lib2to3_parse("""f"{x=}" """)
+        features = black.get_features_used(root)
+        self.assertIn(black.Feature.DEBUG_F_STRINGS, features)
+        versions = black.detect_target_versions(root)
+        self.assertIn(black.TargetVersion.PY38, versions)
+
+        root = black.lib2to3_parse(
+            """f"{x}"\nf'{"="}'\nf'{(x:=5)}'\nf'{f(a="3=")}'\nf'{x:=10}'\n"""
+        )
+        features = black.get_features_used(root)
+        self.assertNotIn(black.Feature.DEBUG_F_STRINGS, features)
+
+        # We don't yet support feature version detection in nested f-strings
+        root = black.lib2to3_parse(
+            """f"heard a rumour that { f'{1+1=}' } ... seems like it could be true" """
+        )
+        features = black.get_features_used(root)
+        self.assertNotIn(black.Feature.DEBUG_F_STRINGS, features)
+
     @patch("black.dump_to_file", dump_to_stderr)
     def test_string_quotes(self) -> None:
         source, expected = read_data("miscellaneous", "string_quotes")

When detecting Python versions, `f"{x=}"` should imply 3.8+
**Describe the bug**

The `=` specifier was added to f-strings in Python 3.8, but Black does not yet distinguish it from any other f-string, and therefore detects the version as 3.6+.  This leads to missed formatting opportunities, and sometimes problems in downstream projects since this is invalid syntax under earlier versions.  (e.g. https://github.com/Zac-HD/shed/issues/31, prompting this issue)

**To Reproduce**

```python
from black import detect_target_versions, parsing

code = parsing.lib2to3_parse("""
f'{x=}'
""")
print(detect_target_versions(code))
```
```
$ python repro.py
{<TargetVersion.PY36: 6>, <TargetVersion.PY37: 7>, <TargetVersion.PY38: 8>, <TargetVersion.PY39: 9>, <TargetVersion.PY310: 10>}
```
tests/test_black.py::BlackTestCase::test_detect_debug_f_strings
tests/test_black.py::BlackTestCase::test_assertFormatEqual tests/test_black.py::BlackTestCase::test_assert_equivalent_different_asts tests/test_black.py::BlackTestCase::test_async_as_identifier tests/test_black.py::BlackTestCase::test_bpo_2142_workaround tests/test_black.py::BlackTestCase::test_bpo_33660_workaround tests/test_black.py::BlackTestCase::test_broken_symlink tests/test_black.py::BlackTestCase::test_check_diff_use_together tests/test_black.py::BlackTestCase::test_code_option tests/test_black.py::BlackTestCase::test_code_option_changed tests/test_black.py::BlackTestCase::test_code_option_check tests/test_black.py::BlackTestCase::test_code_option_check_changed tests/test_black.py::BlackTestCase::test_code_option_color_diff tests/test_black.py::BlackTestCase::test_code_option_config tests/test_black.py::BlackTestCase::test_code_option_diff tests/test_black.py::BlackTestCase::test_code_option_fast tests/test_black.py::BlackTestCase::test_code_option_parent_config tests/test_black.py::BlackTestCase::test_code_option_safe tests/test_black.py::BlackTestCase::test_debug_visitor tests/test_black.py::BlackTestCase::test_detect_pos_only_arguments tests/test_black.py::BlackTestCase::test_empty_ff tests/test_black.py::BlackTestCase::test_endmarker tests/test_black.py::BlackTestCase::test_equivalency_ast_parse_failure_includes_error tests/test_black.py::BlackTestCase::test_experimental_string_processing_warns tests/test_black.py::BlackTestCase::test_expression_diff tests/test_black.py::BlackTestCase::test_expression_diff_with_color tests/test_black.py::BlackTestCase::test_expression_ff tests/test_black.py::BlackTestCase::test_find_project_root tests/test_black.py::BlackTestCase::test_find_pyproject_toml tests/test_black.py::BlackTestCase::test_find_user_pyproject_toml_linux tests/test_black.py::BlackTestCase::test_find_user_pyproject_toml_windows tests/test_black.py::BlackTestCase::test_for_handled_unexpected_eof_error tests/test_black.py::BlackTestCase::test_format_file_contents tests/test_black.py::BlackTestCase::test_get_features_used tests/test_black.py::BlackTestCase::test_get_features_used_decorator tests/test_black.py::BlackTestCase::test_get_features_used_for_future_flags tests/test_black.py::BlackTestCase::test_get_future_imports tests/test_black.py::BlackTestCase::test_invalid_cli_regex tests/test_black.py::BlackTestCase::test_invalid_config_return_code tests/test_black.py::BlackTestCase::test_lib2to3_parse tests/test_black.py::BlackTestCase::test_multi_file_force_py36 tests/test_black.py::BlackTestCase::test_multi_file_force_pyi tests/test_black.py::BlackTestCase::test_newline_comment_interaction tests/test_black.py::BlackTestCase::test_no_src_fails tests/test_black.py::BlackTestCase::test_normalize_path_ignore_windows_junctions_outside_of_root tests/test_black.py::BlackTestCase::test_parse_pyproject_toml tests/test_black.py::BlackTestCase::test_pep_572_version_detection tests/test_black.py::BlackTestCase::test_pipe_force_py36 tests/test_black.py::BlackTestCase::test_pipe_force_pyi tests/test_black.py::BlackTestCase::test_piping tests/test_black.py::BlackTestCase::test_piping_diff tests/test_black.py::BlackTestCase::test_piping_diff_with_color tests/test_black.py::BlackTestCase::test_preserves_line_endings tests/test_black.py::BlackTestCase::test_preserves_line_endings_via_stdin tests/test_black.py::BlackTestCase::test_python37 tests/test_black.py::BlackTestCase::test_read_pyproject_toml tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_and_existing_path tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_empty tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_filename tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_filename_ipynb tests/test_black.py::BlackTestCase::test_reformat_one_with_stdin_filename_pyi tests/test_black.py::BlackTestCase::test_report_normal tests/test_black.py::BlackTestCase::test_report_quiet tests/test_black.py::BlackTestCase::test_report_verbose tests/test_black.py::BlackTestCase::test_required_version_does_not_match_on_minor_version tests/test_black.py::BlackTestCase::test_required_version_does_not_match_version tests/test_black.py::BlackTestCase::test_required_version_matches_partial_version tests/test_black.py::BlackTestCase::test_required_version_matches_version tests/test_black.py::BlackTestCase::test_root_logger_not_used_directly tests/test_black.py::BlackTestCase::test_single_file_force_py36 tests/test_black.py::BlackTestCase::test_single_file_force_pyi tests/test_black.py::BlackTestCase::test_skip_magic_trailing_comma tests/test_black.py::BlackTestCase::test_src_and_code_fails tests/test_black.py::BlackTestCase::test_string_quotes tests/test_black.py::BlackTestCase::test_tab_comment_indentation tests/test_black.py::BlackTestCase::test_works_in_mono_process_only_environment tests/test_black.py::TestCaching::test_get_cache_dir tests/test_black.py::TestCaching::test_cache_broken_file tests/test_black.py::TestCaching::test_cache_single_file_already_cached tests/test_black.py::TestCaching::test_cache_multiple_files tests/test_black.py::TestCaching::test_no_cache_when_writeback_diff[no-color] tests/test_black.py::TestCaching::test_no_cache_when_writeback_diff[with-color] tests/test_black.py::TestCaching::test_output_locking_when_writeback_diff[no-color] tests/test_black.py::TestCaching::test_output_locking_when_writeback_diff[with-color] tests/test_black.py::TestCaching::test_no_cache_when_stdin tests/test_black.py::TestCaching::test_read_cache_no_cachefile tests/test_black.py::TestCaching::test_write_cache_read_cache tests/test_black.py::TestCaching::test_filter_cached tests/test_black.py::TestCaching::test_write_cache_creates_directory_if_needed tests/test_black.py::TestCaching::test_failed_formatting_does_not_get_cached tests/test_black.py::TestCaching::test_write_cache_write_fail tests/test_black.py::TestCaching::test_read_cache_line_lengths tests/test_black.py::TestFileCollection::test_include_exclude tests/test_black.py::TestFileCollection::test_gitignore_used_as_default tests/test_black.py::TestFileCollection::test_exclude_for_issue_1572 tests/test_black.py::TestFileCollection::test_gitignore_exclude tests/test_black.py::TestFileCollection::test_nested_gitignore tests/test_black.py::TestFileCollection::test_invalid_gitignore tests/test_black.py::TestFileCollection::test_invalid_nested_gitignore tests/test_black.py::TestFileCollection::test_empty_include tests/test_black.py::TestFileCollection::test_extend_exclude tests/test_black.py::TestFileCollection::test_symlink_out_of_root_directory tests/test_black.py::TestFileCollection::test_get_sources_with_stdin tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename_and_exclude tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename_and_extend_exclude tests/test_black.py::TestFileCollection::test_get_sources_with_stdin_filename_and_force_exclude