diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 2e416edeffec3b6c77235495ba442f37c3f89f56..2a1272885545eccb0a6244b5597824d3c370f52e 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -21,7 +21,9 @@
 #include <pwd.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/wait.h>
+#include <sys/un.h>
 #include <unistd.h>
 
 #ifdef __APPLE__
@@ -1562,4 +1564,33 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()>
     return std::unique_ptr<InterruptCallback>(res.release());
 }
 
+
+AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
+{
+    AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+    if (!fdSocket)
+        throw SysError("cannot create Unix domain socket");
+
+    closeOnExec(fdSocket.get());
+
+    struct sockaddr_un addr;
+    addr.sun_family = AF_UNIX;
+    if (path.size() >= sizeof(addr.sun_path))
+        throw Error("socket path '%1%' is too long", path);
+    strcpy(addr.sun_path, path.c_str());
+
+    unlink(path.c_str());
+
+    if (bind(fdSocket.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
+        throw SysError("cannot bind to socket '%1%'", path);
+
+    if (chmod(path.c_str(), mode) == -1)
+        throw SysError("changing permissions on '%1%'", path);
+
+    if (listen(fdSocket.get(), 5) == -1)
+        throw SysError("cannot listen on socket '%1%'", path);
+
+    return fdSocket;
+}
+
 }
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 3493e80b5ebfeffa52d3e2714f11accf656459f1..0bb17126839cd18c2e18cd9ffc93c6facc30961a 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -553,4 +553,8 @@ typedef std::function<bool(const Path & path)> PathFilter;
 extern PathFilter defaultPathFilter;
 
 
+/* Create a Unix domain socket in listen mode. */
+AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode);
+
+
 }
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index 799d2bacfaa18d30ba0f91f35c5018d819a1a155..67bf4dfeb3eae40d1ee4d0e3897f6227f2d8aa33 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -156,53 +156,15 @@ static void daemonLoop(char * * argv)
         if (getEnv("LISTEN_PID") != std::to_string(getpid()) || getEnv("LISTEN_FDS") != "1")
             throw Error("unexpected systemd environment variables");
         fdSocket = SD_LISTEN_FDS_START;
+        closeOnExec(fdSocket.get());
     }
 
     /* Otherwise, create and bind to a Unix domain socket. */
     else {
-
-        /* Create and bind to a Unix domain socket. */
-        fdSocket = socket(PF_UNIX, SOCK_STREAM, 0);
-        if (!fdSocket)
-            throw SysError("cannot create Unix domain socket");
-
-        string socketPath = settings.nixDaemonSocketFile;
-
-        createDirs(dirOf(socketPath));
-
-        /* Urgh, sockaddr_un allows path names of only 108 characters.
-           So chdir to the socket directory so that we can pass a
-           relative path name. */
-        if (chdir(dirOf(socketPath).c_str()) == -1)
-            throw SysError("cannot change current directory");
-        Path socketPathRel = "./" + baseNameOf(socketPath);
-
-        struct sockaddr_un addr;
-        addr.sun_family = AF_UNIX;
-        if (socketPathRel.size() >= sizeof(addr.sun_path))
-            throw Error(format("socket path '%1%' is too long") % socketPathRel);
-        strcpy(addr.sun_path, socketPathRel.c_str());
-
-        unlink(socketPath.c_str());
-
-        /* Make sure that the socket is created with 0666 permission
-           (everybody can connect --- provided they have access to the
-           directory containing the socket). */
-        mode_t oldMode = umask(0111);
-        int res = bind(fdSocket.get(), (struct sockaddr *) &addr, sizeof(addr));
-        umask(oldMode);
-        if (res == -1)
-            throw SysError(format("cannot bind to socket '%1%'") % socketPath);
-
-        if (chdir("/") == -1) /* back to the root */
-            throw SysError("cannot change current directory");
-
-        if (listen(fdSocket.get(), 5) == -1)
-            throw SysError(format("cannot listen on socket '%1%'") % socketPath);
+        createDirs(dirOf(settings.nixDaemonSocketFile));
+        fdSocket = createUnixDomainSocket(settings.nixDaemonSocketFile, 0666);
     }
 
-    closeOnExec(fdSocket.get());
-
     /* Loop accepting connections. */
     while (1) {