diff --git a/pseudo_client.c b/pseudo_client.c
index 58e8810..fe111cf 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -1253,8 +1253,31 @@ pseudo_client_path_matches_fd(const char *path, int fd, int nofollow) {
 static int
 client_connect(void) {
 	/* we have a server pid, is it responsive? */
-	struct sockaddr_un sun = { .sun_family = AF_UNIX, .sun_path = PSEUDO_SOCKET };
-	int cwd_fd;
+	struct sockaddr_un sun = { .sun_family = AF_UNIX };
+	struct stat st;
+	int cwd_fd = -1;
+	int use_chdir;
+	int len;
+
+	/* The full socket path can be too long for sun_path, so name the
+	 * state directory by its descriptor under /proc/self/fd.  Unlike
+	 * changing directory, that needs no open("."), which a Landlock
+	 * sandbox can deny, and doesn't move other threads' working
+	 * directory.  Without /proc, or if that path doesn't fit, change
+	 * directory as before.
+	 */
+	len = snprintf(sun.sun_path, sizeof(sun.sun_path), "/proc/self/fd/%d",
+		pseudo_localstate_dir_fd);
+	if (len > 0 && (size_t) len + 1 + strlen(PSEUDO_SOCKET) < sizeof(sun.sun_path) &&
+	    stat(sun.sun_path, &st) == 0 && S_ISDIR(st.st_mode)) {
+		snprintf(sun.sun_path + len, sizeof(sun.sun_path) - len, "/%s",
+			PSEUDO_SOCKET);
+		use_chdir = 0;
+	} else {
+		pseudo_debug(PDBGF_CLIENT, "/proc/self/fd unusable or path too long, changing directory to connect.\n");
+		snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", PSEUDO_SOCKET);
+		use_chdir = 1;
+	}
 
 	connect_fd = socket(PF_UNIX, SOCK_STREAM, 0);
 	connect_fd = pseudo_fd(connect_fd, MOVE_FD);
@@ -1267,40 +1290,46 @@ client_connect(void) {
 	}
 
 	pseudo_debug(PDBGF_CLIENT, "connecting socket...\n");
-	cwd_fd = open(".", O_RDONLY);
-	if (cwd_fd == -1) {
-		pseudo_error("Couldn't stash directory before opening socket: %s",
-			strerror(errno));
-		close(connect_fd);
-		connect_fd = -1;
-		return 1;
-	}
-	if (fchdir(pseudo_localstate_dir_fd) == -1) {
-		pseudo_error("Couldn't chdir to server directory [%d]: %s\n",
-			pseudo_localstate_dir_fd, strerror(errno));
-		close(connect_fd);
-		close(cwd_fd);
-		connect_fd = -1;
-		return 1;
+	if (use_chdir) {
+		cwd_fd = open(".", O_RDONLY);
+		if (cwd_fd == -1) {
+			pseudo_error("Couldn't stash directory before opening socket: %s\n",
+				strerror(errno));
+			close(connect_fd);
+			connect_fd = -1;
+			return 1;
+		}
+		if (fchdir(pseudo_localstate_dir_fd) == -1) {
+			pseudo_error("Couldn't chdir to server directory [%d]: %s\n",
+				pseudo_localstate_dir_fd, strerror(errno));
+			close(connect_fd);
+			close(cwd_fd);
+			connect_fd = -1;
+			return 1;
+		}
 	}
 	if (connect(connect_fd, (struct sockaddr *) &sun, sizeof(sun)) == -1) {
 		char *e = strerror(errno);
 		pseudo_debug(PDBGF_CLIENT, "Can't connect socket to pseudo.socket: (%s)\n", e);
 		pseudo_evlog(PDBGF_CLIENT, "connect failed: %s\n", e);
 		close(connect_fd);
+		if (use_chdir) {
+			if (fchdir(cwd_fd) == -1) {
+				pseudo_error("return to previous directory failed: %s\n",
+					strerror(errno));
+			}
+			close(cwd_fd);
+		}
+		connect_fd = -1;
+		return 1;
+	}
+	if (use_chdir) {
 		if (fchdir(cwd_fd) == -1) {
 			pseudo_error("return to previous directory failed: %s\n",
 				strerror(errno));
 		}
 		close(cwd_fd);
-		connect_fd = -1;
-		return 1;
-	}
-	if (fchdir(cwd_fd) == -1) {
-		pseudo_error("return to previous directory failed: %s\n",
-			strerror(errno));
 	}
-	close(cwd_fd);
 	pseudo_evlog(PDBGF_CLIENT, "socket connect OK.\n");
 	pseudo_debug(PDBGF_CLIENT | PDBGF_VERBOSE, "connected socket.\n");
 	return 0;
