diff --git a/bitbake/lib/bb/fetch2/__init__.py
b/bitbake/lib/bb/fetch2/__init__.py
index ddee4400bb..3d6973a6e5 100644
--- a/bitbake/lib/bb/fetch2/__init__.py
+++ b/bitbake/lib/bb/fetch2/__init__.py
@@ -369,6 +369,13 @@ def decodeurl(url):
         path = location[locidx:]
     elif type.lower() == 'file':
         host = ""
+        # The regex we use above fails on file:// urls for systemd
+        # template files which generally follow the format of
+        # "<unit name>@.service" and split out the unit name
+        # into the user group, so manually put it back
+        if user:
+            location = "%s@%s" % (user, location)
+            user = None
         path = location
     else:
         host = location
@@ -414,7 +421,14 @@ def encodeurl(decoded):
         # Standardise path to ensure comparisons work
         while '//' in path:
             path = path.replace("//", "/")
-        url.append("%s" % urllib.parse.quote(path))
+        urllib_parsed = urllib.parse.urlparse(path).path
+        if type == "file":
+            # urllib.parse.urlparse automatically converts "@" to "%40"
+            # which then fails the bitbake self-tests (the rest of the
+            # stack was able to handle this fine) so convert it back
+            # after the fact.
+            urllib_parsed = urllib_parsed.replace('%40', '@')
+        url.append(urllib_parsed)
     if p:
         for parm in p:
             url.append(";%s=%s" % (parm, p[parm]))
diff --git a/bitbake/lib/bb/tests/fetch.py b/bitbake/lib/bb/tests/fetch.py
index 4e26e38811..dff7780e33 100644
--- a/bitbake/lib/bb/tests/fetch.py
+++ b/bitbake/lib/bb/tests/fetch.py
@@ -1390,6 +1390,7 @@ class URLHandle(unittest.TestCase):
        "file://somelocation;someparam=1": ('file', '', 'somelocation', '',
'', {'someparam': '1'}),
        "https://somesite.com/somerepo.git;user=anyUser:idtoken=1234" :
('https', 'somesite.com', '/somerepo.git', '', '', {'user':
'anyUser:idtoken=1234'}),
        r'git://s.o-me_ONE:!#$%^&*()-_={}[]\|:?,.<>~`@
git.openembedded.org/bitbake;branch=main;protocol=https': ('git', '
