diff --git a/networkx/algorithms/matching.py b/networkx/algorithms/matching.py
index afc505e5f..6bb064dee 100644
--- a/networkx/algorithms/matching.py
+++ b/networkx/algorithms/matching.py
@@ -46,7 +46,7 @@ def maximal_matching(G):
     for u,v in G.edges():
         # If the edge isn't covered, add it to the matching
         # then remove neighborhood of u and v from consideration.
-        if u not in nodes and v not in nodes:
+        if u not in nodes and v not in nodes and u!=v:
             matching.add((u,v))
             nodes.add(u)
             nodes.add(v)

maximal_matching and self loops
`maximal_matching` does allow self-loops
```py
>>> G = nx.Graph([[1,1]])
>>> nx.matching.maximal_matching(G)
{(1, 1)}
```
whereas `max_weight_matching` does not
```py
>>> nx.matching.max_weight_matching(G)
{}
```
Is this expected behaviour? If not, a simple `u != v` check should fix it.
diff --git a/networkx/algorithms/tests/test_matching.py b/networkx/algorithms/tests/test_matching.py
index 05fa8c1b1..ac86da9bc 100644
--- a/networkx/algorithms/tests/test_matching.py
+++ b/networkx/algorithms/tests/test_matching.py
@@ -247,6 +247,20 @@ def test_maximal_matching():
     vset = set(u for u, v in matching)
     vset = vset | set(v for u, v in matching)
 
+    for edge in graph.edges():
+        u, v = edge
+        ok_(len(set([v]) & vset) > 0 or len(set([u]) & vset) > 0, \
+                "not a proper matching!")
+    graph = nx.Graph()
+    graph.add_edge(1, 1)
+    graph.add_edge(1, 2)
+    graph.add_edge(2, 2)
+    graph.add_edge(2, 3)
+    matching = nx.maximal_matching(graph)
+    assert(len(matching)==1)
+    vset = set(u for u, v in matching)
+    vset = vset | set(v for u, v in matching)
+
     for edge in graph.edges():
         u, v = edge
         ok_(len(set([v]) & vset) > 0 or len(set([u]) & vset) > 0, \

pip install -e .
parse_log_pytest
requirements.txt
nose pytest
apt-get update apt-get install -y libgdal-dev graphviz
3.6
requirements/default.txt requirements/test.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
decorator==5.1.1
importlib-metadata==4.8.3
iniconfig==1.1.1
-e git+https://github.com/networkx/networkx.git@e0479d2e090ec301de9612330585e9bc8d1f967c#egg=networkx
nose==1.3.7
packaging==21.3
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
tomli==1.2.3
typing_extensions==4.1.1
zipp==3.6.0

name: networkx
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - decorator==5.1.1
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - nose==1.3.7
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - zipp==3.6.0
prefix: /opt/conda/envs/networkx

networkx/algorithms/tests/test_matching.py::test_maximal_matching
networkx/algorithms/tests/test_matching.py::TestMatching::test_trivial1 networkx/algorithms/tests/test_matching.py::TestMatching::test_trivial2 networkx/algorithms/tests/test_matching.py::TestMatching::test_trivial3 networkx/algorithms/tests/test_matching.py::TestMatching::test_trivial4 networkx/algorithms/tests/test_matching.py::TestMatching::test_trivial5 networkx/algorithms/tests/test_matching.py::TestMatching::test_trivial6 networkx/algorithms/tests/test_matching.py::TestMatching::test_floating_point_weights networkx/algorithms/tests/test_matching.py::TestMatching::test_negative_weights networkx/algorithms/tests/test_matching.py::TestMatching::test_s_blossom networkx/algorithms/tests/test_matching.py::TestMatching::test_s_t_blossom networkx/algorithms/tests/test_matching.py::TestMatching::test_nested_s_blossom networkx/algorithms/tests/test_matching.py::TestMatching::test_nested_s_blossom_relabel networkx/algorithms/tests/test_matching.py::TestMatching::test_nested_s_blossom_expand networkx/algorithms/tests/test_matching.py::TestMatching::test_s_blossom_relabel_expand networkx/algorithms/tests/test_matching.py::TestMatching::test_nested_s_blossom_relabel_expand networkx/algorithms/tests/test_matching.py::TestMatching::test_nasty_blossom1 networkx/algorithms/tests/test_matching.py::TestMatching::test_nasty_blossom2 networkx/algorithms/tests/test_matching.py::TestMatching::test_nasty_blossom_least_slack networkx/algorithms/tests/test_matching.py::TestMatching::test_nasty_blossom_augmenting networkx/algorithms/tests/test_matching.py::TestMatching::test_nasty_blossom_expand_recursively networkx/algorithms/tests/test_matching.py::test_maximal_matching_ordering
networkx/algorithms/matching.py
networkx/algorithms/matching.py