diff --git a/lib/cache/api.c b/lib/cache/api.c
index 3e8351fad403d3399bf3d6d76c39c7c50017b141..d7794eca988d3802cf02771dec1c80a8052eb095 100644
--- a/lib/cache/api.c
+++ b/lib/cache/api.c
@@ -135,8 +135,8 @@ int kr_cache_open(struct kr_cache *cache, const struct kr_cdb_api *api, struct k
 		ret = cache->api->open(&cache->db, &cache->stats, &opts2, mm);
 	}
 
-	char *fpath;
-	if (asprintf(&fpath, "%s/data.mdb", opts->path) > 0) {
+	char *fpath = kr_absolutize_path(opts->path, "data.mdb");
+	if (fpath) {
 		kr_cache_emergency_file_to_remove = fpath;
 	} else {
 		assert(false); /* non-critical, but still */
diff --git a/lib/cache/cdb_lmdb.c b/lib/cache/cdb_lmdb.c
index 3b986df82166ef79dc35f5a199efa4c2228df376..b56d8335e904666a3c60a4eb49a085882ed4a749 100644
--- a/lib/cache/cdb_lmdb.c
+++ b/lib/cache/cdb_lmdb.c
@@ -297,7 +297,7 @@ static int cdb_open_env(struct lmdb_env *env, const char *path, const size_t map
 	ret = mdb_env_create(&env->env);
 	if (ret != MDB_SUCCESS) return lmdb_error(ret);
 
-	env->mdb_data_path = kr_strcatdup(2, path, "/data.mdb");
+	env->mdb_data_path = kr_absolutize_path(path, "data.mdb");
 	if (!env->mdb_data_path) {
 		ret = ENOMEM;
 		goto error_sys;
diff --git a/lib/utils.c b/lib/utils.c
index fcba71bb0cb19f0a6d1f03e67ce704dbfbea18f7..97179409931658bbf93bf198884387c1d6e1c7db 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -210,6 +210,31 @@ char* kr_strcatdup(unsigned n, ...)
 	return result;
 }
 
+char * kr_absolutize_path(const char *dirname, const char *fname)
+{
+	assert(dirname && fname);
+	char *result;
+	int aret;
+	if (dirname[0] == '/') { // absolute path is easier
+		aret = asprintf(&result, "%s/%s", dirname, fname);
+	} else { // relative path, but don't resolve symlinks
+		char buf[PATH_MAX];
+		const char *cwd = getcwd(buf, sizeof(buf));
+		if (!cwd)
+			return NULL; // errno has been set already
+		if (strcmp(dirname, ".") == 0) {
+			// get rid of one common case of extraneous "./"
+			aret = asprintf(&result, "%s/%s", cwd, fname);
+		} else {
+			aret = asprintf(&result, "%s/%s/%s", cwd, dirname, fname);
+		}
+	}
+	if (aret > 0)
+		return result;
+	errno = -aret;
+	return NULL;
+}
+
 int kr_memreserve(void *baton, void **mem, size_t elm_size, size_t want, size_t *have)
 {
     if (*have >= want) {
diff --git a/lib/utils.h b/lib/utils.h
index 48748d2bb5a61ffa3b32409f19a7c53b491c4ad9..3b017951294208a5c87719d68031cea5decb89ce 100644
--- a/lib/utils.h
+++ b/lib/utils.h
@@ -223,6 +223,11 @@ typedef array_t(ranked_rr_array_entry_t *) ranked_rr_array_t;
 KR_EXPORT
 char* kr_strcatdup(unsigned n, ...);
 
+/** Construct absolute file path, without resolving symlinks.
+ * \return malloc-ed string or NULL (+errno in that case) */
+KR_EXPORT
+char * kr_absolutize_path(const char *dirname, const char *fname);
+
 /** You probably want kr_rand_* convenience functions instead.
  * This is a buffered version of gnutls_rnd(GNUTLS_RND_NONCE, ..) */
 KR_EXPORT