diff --git a/CHANGES/5877.bugfix b/CHANGES/5877.bugfix
new file mode 100644
index 00000000000..5a8108a9a45
--- /dev/null
+++ b/CHANGES/5877.bugfix
@@ -0,0 +1 @@
+Uses :py:class:`~asyncio.ThreadedChildWatcher` under POSIX to allow setting up test loop in non-main thread.
diff --git a/aiohttp/test_utils.py b/aiohttp/test_utils.py
index 06155bae19f..36a860b0171 100644
--- a/aiohttp/test_utils.py
+++ b/aiohttp/test_utils.py
@@ -497,7 +497,7 @@ def setup_test_loop(
             # * https://stackoverflow.com/a/58614689/595220
             # * https://bugs.python.org/issue35621
             # * https://github.com/python/cpython/pull/14344
-            watcher = asyncio.MultiLoopChildWatcher()
+            watcher = asyncio.ThreadedChildWatcher()
         except AttributeError:  # Python < 3.8
             watcher = asyncio.SafeChildWatcher()
         watcher.attach_loop(loop)
diff --git a/tests/test_loop.py b/tests/test_loop.py
index 50fe5a8ad69..b72771a175a 100644
--- a/tests/test_loop.py
+++ b/tests/test_loop.py
@@ -6,14 +6,15 @@
 import pytest
 
 from aiohttp import web
-from aiohttp.test_utils import AioHTTPTestCase
+from aiohttp.helpers import PY_38
+from aiohttp.test_utils import AioHTTPTestCase, loop_context
 
 
 @pytest.mark.skipif(
     platform.system() == "Windows", reason="the test is not valid for Windows"
 )
 async def test_subprocess_co(loop: Any) -> None:
-    assert threading.current_thread() is threading.main_thread()
+    assert PY_38 or threading.current_thread() is threading.main_thread()
     proc = await asyncio.create_subprocess_shell(
         "exit 0",
         stdin=asyncio.subprocess.DEVNULL,
@@ -43,3 +44,24 @@ def test_default_loop(self) -> None:
 
 def test_default_loop(loop: Any) -> None:
     assert asyncio.get_event_loop() is loop
+
+
+@pytest.mark.xfail(not PY_38, reason="ThreadedChildWatcher is only available in 3.8+")
+def test_setup_loop_non_main_thread() -> None:
+    child_exc = None
+
+    def target() -> None:
+        try:
+            with loop_context() as loop:
+                assert asyncio.get_event_loop() is loop
+                loop.run_until_complete(test_subprocess_co(loop))
+        except Exception as exc:
+            nonlocal child_exc
+            child_exc = exc
+
+    # Ensures setup_test_loop can be called by pytest-xdist in non-main thread.
+    t = threading.Thread(target=target)
+    t.start()
+    t.join()
+
+    assert child_exc is None