diff --git a/swh/loader/mercurial/hgutil.py b/swh/loader/mercurial/hgutil.py
--- a/swh/loader/mercurial/hgutil.py
+++ b/swh/loader/mercurial/hgutil.py
@@ -4,10 +4,14 @@
 # See top-level LICENSE file for more information
 
 import io
-from multiprocessing import Process, Queue
+import os
+import signal
+import time
 import traceback
 from typing import Dict, NewType
 
+from billiard import Process, Queue
+
 # The internal Mercurial API is not guaranteed to be stable.
 from mercurial import context, error, hg, smartset, util  # type: ignore
 import mercurial.ui  # type: ignore
@@ -68,7 +72,7 @@
         raise e
 
 
-def clone(src: str, dest: str, timeout: int) -> None:
+def clone(src: str, dest: str, timeout: float) -> None:
     """Clone a repository with timeout.
 
     Args:
@@ -83,10 +87,14 @@
 
     if process.is_alive():
         process.terminate()
-        process.join(1)
+        # Can't use `process.join(1)` here, billiard appears to be bugged
+        # https://github.com/celery/billiard/issues/270
+        time.sleep(1)
+        killed = False
         if process.is_alive():
-            process.kill()
-        raise CloneTimeout(src, timeout)
+            killed = True
+            os.kill(process.pid, signal.SIGKILL)
+        raise CloneTimeout(src, timeout, killed)
 
     if not errors.empty():
         raise CloneFailure(src, dest, errors.get())
diff --git a/swh/loader/mercurial/tests/test_hgutil.py b/swh/loader/mercurial/tests/test_hgutil.py
--- a/swh/loader/mercurial/tests/test_hgutil.py
+++ b/swh/loader/mercurial/tests/test_hgutil.py
@@ -2,7 +2,7 @@
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU General Public License version 3, or any later version
 # See top-level LICENSE file for more information
-
+import signal
 import time
 import traceback
 
@@ -15,16 +15,19 @@
 def test_clone_timeout(monkeypatch):
     src = "https://www.mercurial-scm.org/repo/hello"
     dest = "/dev/null"
-    timeout = 1
+    timeout = 0.1
 
     def clone(*args, **kwargs):
-        time.sleep(5)
+        # ignore SIGTERM to force sigkill
+        signal.signal(signal.SIGTERM, lambda signum, frame: None)
+        time.sleep(2)
 
     monkeypatch.setattr(hg, "clone", clone)
 
     with pytest.raises(hgutil.CloneTimeout) as e:
         hgutil.clone(src, dest, timeout)
-    assert e.value.args == (src, timeout)
+    killed = True
+    assert e.value.args == (src, timeout, killed)
 
 
 def test_clone_error(caplog, tmp_path, monkeypatch):