diff --git a/tests/misc-tests/065-btrfstune-simple-quota/test.sh b/tests/misc-tests/065-btrfstune-simple-quota/test.sh
new file mode 100755
index 000000000..d7ccaf4e9
--- /dev/null
+++ b/tests/misc-tests/065-btrfstune-simple-quota/test.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Verify btrfstune for enabling and removing simple quotas
+
+source "$TEST_TOP/common" || exit
+source "$TEST_TOP/common.convert" || exit
+
+check_experimental_build
+setup_root_helper
+prepare_test_dev
+
+# Create the fs without simple quota
+run_check_mkfs_test_dev
+run_check_mount_test_dev
+populate_fs
+run_check_umount_test_dev
+# Enable simple quotas
+run_check $SUDO_HELPER "$TOP/btrfstune" --enable-simple-quota "$TEST_DEV"
+run_check_mount_test_dev
+run_check $SUDO_HELPER dd if=/dev/zero of="$TEST_MNT"/file2 bs=1M count=1
+run_check_umount_test_dev
+run_check $SUDO_HELPER "$TOP/btrfs" check "$TEST_DEV"
+
+# Populate new fs with simple quotas enabled
+run_check_mkfs_test_dev -O squota
+run_check_mount_test_dev
+populate_fs
+run_check_umount_test_dev
+# Remove simple quotas
+run_check $SUDO_HELPER "$TOP/btrfstune" --remove-simple-quota "$TEST_DEV"
+run_check_mount_test_dev
+run_check $SUDO_HELPER dd if=/dev/zero of="$TEST_MNT"/file3 bs=1M count=1
+run_check_umount_test_dev
+run_check $SUDO_HELPER "$TOP/btrfs" check "$TEST_DEV"
diff --git a/tune/main.c b/tune/main.c
index cb93d2cb3..6ef8bbe2d 100644
--- a/tune/main.c
+++ b/tune/main.c
@@ -104,6 +104,7 @@ static const char * const tune_usage[] = {
 	OPTLINE("-n", "enable no-holes feature (mkfs: no-holes, more efficient sparse file representation)"),
 	OPTLINE("-S <0|1>", "set/unset seeding status of a device"),
 	OPTLINE("--enable-simple-quota", "enable simple quotas on the file system. (mkfs: squota)"),
+	OPTLINE("--remove-simple-quota", "remove simple quotas from the file system."),
 	OPTLINE("--convert-to-block-group-tree", "convert filesystem to track block groups in "
 			"the separate block-group-tree instead of extent tree (sets the incompat bit)"),
 	OPTLINE("--convert-from-block-group-tree",
@@ -198,6 +199,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
 	int ret;
 	u64 super_flags = 0;
 	int quota = 0;
+	int remove_simple_quota = 0;
 	int fd = -1;
 	int oflags = O_RDWR;
 
@@ -209,7 +211,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
 		       GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE,
 		       GETOPT_VAL_ENABLE_FREE_SPACE_TREE,
 		       GETOPT_VAL_ENABLE_SIMPLE_QUOTA,
-
+		       GETOPT_VAL_REMOVE_SIMPLE_QUOTA,
 		};
 		static const struct option long_options[] = {
 			{ "help", no_argument, NULL, GETOPT_VAL_HELP},
@@ -221,6 +223,8 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
 				GETOPT_VAL_ENABLE_FREE_SPACE_TREE},
 			{ "enable-simple-quota", no_argument, NULL,
 				GETOPT_VAL_ENABLE_SIMPLE_QUOTA },
+			{ "remove-simple-quota", no_argument, NULL,
+				GETOPT_VAL_REMOVE_SIMPLE_QUOTA},
 #if EXPERIMENTAL
 			{ "csum", required_argument, NULL, GETOPT_VAL_CSUM },
 #endif
@@ -288,6 +292,10 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
 			quota = 1;
 			btrfstune_cmd_groups[QGROUP] = true;
 			break;
+		case GETOPT_VAL_REMOVE_SIMPLE_QUOTA:
+			remove_simple_quota = 1;
+			btrfstune_cmd_groups[QGROUP] = true;
+			break;
 #if EXPERIMENTAL
 		case GETOPT_VAL_CSUM:
 			btrfs_warn_experimental(
@@ -535,6 +543,12 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
 			goto out;
 	}
 
+	if (remove_simple_quota) {
+		ret = remove_squota(root->fs_info);
+		if (ret)
+			goto out;
+	}
+
 out:
 	if (ret < 0) {
 		fs_info->readonly = 1;
diff --git a/tune/quota.c b/tune/quota.c
index a14f45307..16b2b3fb6 100644
--- a/tune/quota.c
+++ b/tune/quota.c
@@ -6,6 +6,166 @@
 #include "common/messages.h"
 #include "tune/tune.h"
 
+static int remove_quota_tree(struct btrfs_fs_info *fs_info)
+{
+	int ret;
+	struct btrfs_root *quota_root = fs_info->quota_root;
+	struct btrfs_root *tree_root = fs_info->tree_root;
+	struct btrfs_super_block *sb = fs_info->super_copy;
+	int super_flags = btrfs_super_incompat_flags(sb);
+	struct btrfs_trans_handle *trans;
+
+	trans = btrfs_start_transaction(quota_root, 0);
+	ret = btrfs_clear_tree(trans, quota_root);
+	if (ret) {
+		btrfs_abort_transaction(trans, ret);
+		return ret;
+	}
+
+	ret = btrfs_delete_and_free_root(trans, quota_root);
+	if (ret) {
+		btrfs_abort_transaction(trans, ret);
+		return ret;
+	}
+	fs_info->quota_root = NULL;
+	super_flags &= ~BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA;
+	btrfs_set_super_incompat_flags(sb, super_flags);
+	btrfs_commit_transaction(trans, tree_root);
+	return 0;
+}
+
+/*
+ * Given a pointer (ptr) into DATAi (i = slot), and an amount to shift,
+ * move all the data to the left (slots >= slot) of that ptr to the right by
+ * the shift amount. This overwrites the shift bytes after ptr, effectively
+ * removing them from the item data. We must update affected item sizes (only
+ * at slot) and offsets (slots >= slot).
+ *
+ * Leaf view, using '-' to show shift scale:
+ * Before:
+ * [ITEM0,...,ITEMi,...,ITEMn,-------,DATAn,...,[---DATAi---],...,DATA0]
+ * After:
+ * [ITEM0,...,ITEMi,...,ITEMn,--------,DATAn,...,[--DATAi---],...,DATA0]
+ *
+ * Zooming in on DATAi
+ * (ptr points at the start of the Ys, and shift is length of the Ys)
+ * Before:
+ * ...[DATAi+1][XXXXXXXXXXXXYYYYYYYYYYYYYYYYXXXXXXX][DATAi-1]...
+ * After:
+ * ...................[DATAi+1][XXXXXXXXXXXXXXXXXXX][DATAi-1]...
+ * Note that DATAi-1 and smaller are not affected.
+ */
+static void shift_leaf_data(struct btrfs_trans_handle *trans,
+			    struct extent_buffer *leaf, int slot,
+			    unsigned long ptr, u32 shift)
+{
+	u32 nr = btrfs_header_nritems(leaf);
+	u32 leaf_data_off = btrfs_item_ptr_offset(leaf, nr - 1);
+	u32 len = ptr - leaf_data_off;
+	u32 new_size = btrfs_item_size(leaf, slot) - shift;
+	for (int i = slot; i < nr; i++) {
+		u32 old_item_offset = btrfs_item_offset(leaf, i);
+		btrfs_set_item_offset(leaf, i, old_item_offset + shift);
+	}
+	memmove_extent_buffer(leaf, leaf_data_off + shift, leaf_data_off, len);
+	btrfs_set_item_size(leaf, slot, new_size);
+	btrfs_set_header_generation(leaf, trans->transid);
+	btrfs_mark_buffer_dirty(leaf);
+}
+
+/*
+ * Iterate over the extent tree and for each EXTENT_DATA item that has an inline
+ * ref of type OWNER_REF, shift that leaf to eliminate the owner ref.
+ *
+ * Note: we use a search_slot per leaf rather than find_next_leaf to get the
+ * needed CoW-ing and rebalancing for each leaf and its path up to the root.
+ */
+static int remove_owner_refs(struct btrfs_fs_info *fs_info)
+{
+	struct btrfs_trans_handle *trans;
+	struct btrfs_root *extent_root;
+	struct btrfs_key key;
+	struct extent_buffer *leaf;
+	struct btrfs_path path = { 0 };
+	int slot;
+	int ret;
+
+	extent_root = btrfs_extent_root(fs_info, 0);
+
+	trans = btrfs_start_transaction(extent_root, 0);
+
+	key.objectid = 0;
+	key.type = BTRFS_EXTENT_ITEM_KEY;
+	key.offset = 0;
+
+search_slot:
+	ret = btrfs_search_slot(trans, extent_root, &key, &path, 1, 1);
+	if (ret < 0)
+		return ret;
+	leaf = path.nodes[0];
+	slot = path.slots[0];
+
+	while (1) {
+		struct btrfs_key found_key;
+		struct btrfs_extent_item *ei;
+		struct btrfs_extent_inline_ref *iref;
+		u8 type;
+		unsigned long ptr;
+		unsigned long item_end;
+
+		if (slot >= btrfs_header_nritems(leaf)) {
+			ret = btrfs_next_leaf(extent_root, &path);
+			if (ret < 0) {
+				break;
+			} else if (ret) {
+				ret = 0;
+				break;
+			}
+			leaf = path.nodes[0];
+			slot = path.slots[0];
+			btrfs_item_key_to_cpu(leaf, &key, slot);
+			btrfs_release_path(&path);
+			goto search_slot;
+		}
+
+		btrfs_item_key_to_cpu(leaf, &found_key, slot);
+		if (found_key.type != BTRFS_EXTENT_ITEM_KEY)
+			goto next;
+		ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
+		ptr = (unsigned long)(ei + 1);
+		item_end = (unsigned long)ei + btrfs_item_size(leaf, slot);
+		/* No inline extent references; accessing type is invalid. */
+		if (ptr > item_end)
+			goto next;
+		iref = (struct btrfs_extent_inline_ref *)ptr;
+		type = btrfs_extent_inline_ref_type(leaf, iref);
+		if (type == BTRFS_EXTENT_OWNER_REF_KEY)
+			shift_leaf_data(trans, leaf, slot, ptr, sizeof(*iref));
+next:
+		slot++;
+	}
+	btrfs_release_path(&path);
+
+	ret = btrfs_commit_transaction(trans, extent_root);
+	if (ret < 0) {
+		errno = -ret;
+		error_msg(ERROR_MSG_COMMIT_TRANS, "%m");
+		return ret;
+	}
+	return 0;
+}
+
+int remove_squota(struct btrfs_fs_info *fs_info)
+{
+	int ret;
+
+	ret = remove_owner_refs(fs_info);
+	if (ret)
+		return ret;
+
+	return remove_quota_tree(fs_info);
+}
+
 static int create_qgroup(struct btrfs_fs_info *fs_info,
 			 struct btrfs_trans_handle *trans,
 			 u64 qgroupid)
diff --git a/tune/tune.h b/tune/tune.h
index 397cfe4f3..a41ba78b7 100644
--- a/tune/tune.h
+++ b/tune/tune.h
@@ -33,5 +33,6 @@ int convert_to_extent_tree(struct btrfs_fs_info *fs_info);
 int btrfs_change_csum_type(struct btrfs_fs_info *fs_info, u16 new_csum_type);
 
 int enable_quota(struct btrfs_fs_info *fs_info, bool simple);
+int remove_squota(struct btrfs_fs_info *fs_info);
 
 #endif
