diff --git a/Documentation/ch-compression.rst b/Documentation/ch-compression.rst
index a9ec8f1e..f7cdda86 100644
--- a/Documentation/ch-compression.rst
+++ b/Documentation/ch-compression.rst
@@ -25,8 +25,8 @@ LZO
         * good backward compatibility
 ZSTD
         * compression comparable to ZLIB with higher compression/decompression speeds and different ratio
-        * levels: 1 to 15, mapped directly (higher levels are not available)
-        * since 4.14, levels since 5.1
+        * levels: -15 to 15, mapped directly, default is 3
+        * since 4.14, levels 1 to 15 since 5.1, -15 to -1 since 6.15
 
 The differences depend on the actual data set and cannot be expressed by a
 single number or recommendation. Higher levels consume more CPU time and may
@@ -78,7 +78,7 @@ Compression levels
 
 The level support of ZLIB has been added in v4.14, LZO does not support levels
 (the kernel implementation provides only one), ZSTD level support has been added
-in v5.1.
+in v5.1 and negative levels since v6.15.
 
 There are 9 levels of ZLIB supported (1 to 9), mapping 1:1 from the mount option
 to the algorithm defined level. The default is level 3, which provides the
@@ -86,8 +86,8 @@ reasonably good compression ratio and is still reasonably fast. The difference
 in compression gain of levels 7, 8 and 9 is comparable but the higher levels
 take longer.
 
-The ZSTD support includes levels 1 to 15, a subset of full range of what ZSTD
-provides. Levels 1-3 are real-time, 4-8 slower with improved compression and
+The ZSTD support includes levels -15 to 15, a subset of full range of what ZSTD
+provides. Levels -15-3 are real-time, 4-8 slower with improved compression and
 9-15 try even harder though the resulting size may not be significantly improved.
 
 Level 0 always maps to the default. The compression level does not affect
diff --git a/cmds/filesystem.c b/cmds/filesystem.c
index d2605bda..f3f93ff7 100644
--- a/cmds/filesystem.c
+++ b/cmds/filesystem.c
@@ -962,6 +962,7 @@ static const char * const cmd_filesystem_defrag_usage[] = {
 	"",
 	OPTLINE("-r", "defragment files recursively"),
 	OPTLINE("-c[zlib,lzo,zstd]", "compress the file while defragmenting, optional parameter (no space in between)"),
+	OPTLINE("-L|--level level", "use given compression level if enabled (zlib supports levels 1-9, zstd -15-15, and 0 selects the default level)"),
 	OPTLINE("-f", "flush data to disk immediately after defragmenting"),
 	OPTLINE("-s start", "defragment only from byte onward"),
 	OPTLINE("-l len", "defragment only up to len bytes"),
@@ -1066,6 +1067,7 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 	bool recursive = false;
 	int ret = 0;
 	int compress_type = BTRFS_COMPRESS_NONE;
+	int compress_level = 0;
 
 	/*
 	 * Kernel 4.19+ supports defragmention of files open read-only,
@@ -1095,18 +1097,18 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 	if (bconf.verbose != BTRFS_BCONF_UNSET)
 		bconf.verbose++;
 
-	defrag_global_errors = 0;
 	defrag_global_errors = 0;
 	optind = 0;
 	while(1) {
 		enum { GETOPT_VAL_STEP = GETOPT_VAL_FIRST };
 		static const struct option long_options[] = {
+			{ "level", required_argument, NULL, 'L' },
 			{ "step", required_argument, NULL, GETOPT_VAL_STEP },
 			{ NULL, 0, NULL, 0 }
 		};
 		int c;
 
-		c = getopt_long(argc, argv, "vrc::fs:l:t:", long_options, NULL);
+		c = getopt_long(argc, argv, "vrc::L:fs:l:t:", long_options, NULL);
 		if (c < 0)
 			break;
 
@@ -1116,6 +1118,18 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 			if (optarg)
 				compress_type = parse_compress_type_arg(optarg);
 			break;
+		case 'L':
+			/*
+			 * Do not enforce any limits here, kernel will do itself
+			 * based on what's supported by the running version.
+			 * Just clip to the s8 type of the API.
+			 */
+			compress_level = atoi(optarg);
+			if (compress_level < -128)
+				compress_level = -128;
+			else if (compress_level > 127)
+				compress_level = 127;
+			break;
 		case 'f':
 			flush = true;
 			break;
@@ -1165,7 +1179,12 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 	defrag_global_range.extent_thresh = (u32)thresh;
 	if (compress_type) {
 		defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
-		defrag_global_range.compress_type = compress_type;
+		if (compress_level) {
+			defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL;
+			defrag_global_range.compress.type = compress_type;
+			defrag_global_range.compress.level= compress_level;
+		} else
+			defrag_global_range.compress_type = compress_type;
 	}
 	if (flush)
 		defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
diff --git a/kernel-shared/uapi/btrfs.h b/kernel-shared/uapi/btrfs.h
index 6649436c..d2609777 100644
--- a/kernel-shared/uapi/btrfs.h
+++ b/kernel-shared/uapi/btrfs.h
@@ -645,7 +645,9 @@ _static_assert(sizeof(struct btrfs_ioctl_clone_range_args) == 32);
  */
 #define BTRFS_DEFRAG_RANGE_COMPRESS 1
 #define BTRFS_DEFRAG_RANGE_START_IO 2
+#define BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL 4
 #define BTRFS_DEFRAG_RANGE_FLAGS_SUPP	(BTRFS_DEFRAG_RANGE_COMPRESS |		\
+					 BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL |	\
 					 BTRFS_DEFRAG_RANGE_START_IO)
 
 struct btrfs_ioctl_defrag_range_args {
@@ -673,7 +675,13 @@ struct btrfs_ioctl_defrag_range_args {
 	 * for this defrag operation.  If unspecified, zlib will
 	 * be used
 	 */
-	__u32 compress_type;
+	union {
+		__u32 compress_type;
+		struct {
+			__u8 type;
+			__s8 level;
+		} compress;
+	};
 
 	/* spare for later */
 	__u32 unused[4];
diff --git a/libbtrfs/ioctl.h b/libbtrfs/ioctl.h
index 7b53a531..08681f2e 100644
--- a/libbtrfs/ioctl.h
+++ b/libbtrfs/ioctl.h
@@ -398,6 +398,7 @@ struct btrfs_ioctl_clone_range_args {
 /* flags for the defrag range ioctl */
 #define BTRFS_DEFRAG_RANGE_COMPRESS 1
 #define BTRFS_DEFRAG_RANGE_START_IO 2
+#define BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL 4
 
 #define BTRFS_SAME_DATA_DIFFERS	1
 /* For extent-same ioctl */
diff --git a/libbtrfsutil/btrfs.h b/libbtrfsutil/btrfs.h
index 8e5681c7..ebc9fc2a 100644
--- a/libbtrfsutil/btrfs.h
+++ b/libbtrfsutil/btrfs.h
@@ -608,7 +608,9 @@ struct btrfs_ioctl_clone_range_args {
  */
 #define BTRFS_DEFRAG_RANGE_COMPRESS 1
 #define BTRFS_DEFRAG_RANGE_START_IO 2
+#define BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL 4
 #define BTRFS_DEFRAG_RANGE_FLAGS_SUPP	(BTRFS_DEFRAG_RANGE_COMPRESS |		\
+					 BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL |	\
 					 BTRFS_DEFRAG_RANGE_START_IO)
 
 struct btrfs_ioctl_defrag_range_args {
@@ -636,7 +638,13 @@ struct btrfs_ioctl_defrag_range_args {
 	 * for this defrag operation.  If unspecified, zlib will
 	 * be used
 	 */
-	__u32 compress_type;
+	union {
+		__u32 compress_type;
+		struct {
+			__u8 type;
+			__s8 level;
+		} compress;
+	};
 
 	/* spare for later */
 	__u32 unused[4];
