diff --git a/balloon.c b/balloon.c
index c814102..5b98aa7 100644
--- a/balloon.c
+++ b/balloon.c
@@ -35,17 +35,29 @@
 #include "qapi/qmp/qjson.h"
 #include "exec/ram_addr.h"
 #include "migration/vmstate.h"
+#include "migration/migration.h"
+#include "qemu/error-report.h"
 
 #define BALLOON_BMAP_NAME       "balloon.bmap"
 #define BALLOON_BMAP_SIZE(nr)   (nr / (((1UL << balloon_bitmap_pfn_shift) * \
                                          sizeof(unsigned long)) - 1))
 
+typedef enum {
+    BALLOON_BITMAP_NONE = 0,
+    BALLOON_BITMAP_INIT,
+    BALLOON_BITMAP_ENABLE,
+    BALLOON_BITMAP_DISABLE,
+    BALLOON_BITMAP_DISABLE_FROM_GUEST,
+} BalloonBitmapState;
+
 static QEMUBalloonEvent *balloon_event_fn;
 static QEMUBalloonStatus *balloon_stat_fn;
+static QEMUBalloonTellHost *balloon_tellhost_fn;
 static QemuMutex balloon_bmap_mutex;
 static MemoryRegion *bmap_mr;
 static unsigned long *bmap;
 static unsigned int balloon_bitmap_pfn_shift;
+static BalloonBitmapState balloon_bitmap_state;
 static void *balloon_opaque;
 static bool balloon_inhibited;
 
@@ -86,9 +98,11 @@ static bool have_balloon(Error **errp)
 
 int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
                              QEMUBalloonStatus *stat_func,
+                             QEMUBalloonTellHost *tellhost_func,
                              void *opaque, int balloon_pfn_shift)
 {
-    if (balloon_event_fn || balloon_stat_fn || balloon_opaque) {
+    if (balloon_event_fn || balloon_stat_fn ||
+        balloon_tellhost_fn || balloon_opaque) {
         /* We're already registered one balloon handler.  How many can
          * a guest really have?
          */
@@ -96,6 +110,7 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
     }
     balloon_event_fn = event_func;
     balloon_stat_fn = stat_func;
+    balloon_tellhost_fn = tellhost_func;
     balloon_bitmap_pfn_shift = balloon_pfn_shift;
     balloon_opaque = opaque;
 
@@ -108,6 +123,7 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
     vmstate_register_ram_global(bmap_mr);
     bmap = memory_region_get_ram_ptr(bmap_mr);
     bitmap_clear(bmap, 0, (last_ram_offset() >> balloon_bitmap_pfn_shift));
+    balloon_bitmap_state = BALLOON_BITMAP_INIT;
     return 0;
 }
 
@@ -118,8 +134,11 @@ void qemu_remove_balloon_handler(void *opaque)
     }
     object_unref(OBJECT(bmap_mr));
     bmap = NULL;
+    balloon_bitmap_state = BALLOON_BITMAP_NONE;
+
     balloon_event_fn = NULL;
     balloon_stat_fn = NULL;
+    balloon_tellhost_fn = NULL;
     balloon_opaque = NULL;
 }
 
@@ -154,7 +173,7 @@ void qmp_balloon(int64_t target, Error **errp)
 /* Should be called with balloon bitmap mutex lock held */
 void qemu_balloon_bitmap_update(ram_addr_t addr, int deflate)
 {
-    unsigned long offset = 0;
+    unsigned long offset = 0, byte_offset;
 
     if (!bmap) {
         return;
@@ -165,6 +184,11 @@ void qemu_balloon_bitmap_update(ram_addr_t addr, int deflate)
     } else {
         clear_bit(offset, bmap);
     }
+
+    if (balloon_bitmap_state == BALLOON_BITMAP_ENABLE) {
+        byte_offset = offset / BITS_PER_BYTE;
+        memory_region_set_dirty(bmap_mr, byte_offset, BITS_PER_BYTE);
+    }
 }
 
 /* Handle Ram hotplug case, only called in case old < new */
@@ -205,3 +229,33 @@ void qemu_balloon_bitmap_extend(RAMBlock *new_block,
     qemu_mutex_unlock_balloon_bitmap();
     g_free(old_bitmap);
 }
+
+void qemu_balloon_bitmap_setup(void)
+{
+    Error *err = NULL;
+    Error **errp = &err;
+    int ret = -1;
+
+    if (!bmap || balloon_bitmap_state != BALLOON_BITMAP_INIT) {
+        return;
+    }
+
+    if (!have_balloon(errp) || !migrate_skip_balloon()) {
+        balloon_bitmap_state = BALLOON_BITMAP_DISABLE;
+    } else {
+        balloon_tellhost_fn(balloon_opaque, &ret);
+        if (ret != 1) {
+            error_report("Guest balloon driver does not support "
+                         "MUST_TELL_HOST feature, enabling skip-balloon "
+                         "may not have any effect");
+            balloon_bitmap_state = BALLOON_BITMAP_DISABLE_FROM_GUEST;
+        } else {
+            balloon_bitmap_state = BALLOON_BITMAP_ENABLE;
+        }
+    }
+
+    if (bmap && (balloon_bitmap_state == BALLOON_BITMAP_DISABLE_FROM_GUEST ||
+                 balloon_bitmap_state == BALLOON_BITMAP_DISABLE)) {
+        memory_region_ram_resize(bmap_mr, 0, &error_fatal);
+    }
+}
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 33750f7..5031fa8 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -388,6 +388,7 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
     VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
     f |= dev->host_features;
     virtio_add_feature(&f, VIRTIO_BALLOON_F_STATS_VQ);
+    virtio_add_feature(&f, VIRTIO_BALLOON_F_MUST_TELL_HOST);
     return f;
 }
 
@@ -398,6 +399,14 @@ static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
                                              VIRTIO_BALLOON_PFN_SHIFT);
 }
 
+static void virtio_balloon_tellhost_supported(void *opaque, int *status)
+{
+    VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+    *status = virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+}
+
 static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
 {
     VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
@@ -460,6 +469,7 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
 
     ret = qemu_add_balloon_handler(virtio_balloon_to_target,
                                    virtio_balloon_stat,
+                                   virtio_balloon_tellhost_supported,
                                    s, VIRTIO_BALLOON_PFN_SHIFT);
 
     if (ret < 0) {
diff --git a/include/migration/migration.h b/include/migration/migration.h
index ac2c12c..6c1d1af 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -267,6 +267,7 @@ void migrate_del_blocker(Error *reason);
 
 bool migrate_postcopy_ram(void);
 bool migrate_zero_blocks(void);
+bool migrate_skip_balloon(void);
 
 bool migrate_auto_converge(void);
 
diff --git a/include/sysemu/balloon.h b/include/sysemu/balloon.h
index ebaa292..8cf5a2f 100644
--- a/include/sysemu/balloon.h
+++ b/include/sysemu/balloon.h
@@ -18,9 +18,11 @@
 
 typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
 typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
+typedef void (QEMUBalloonTellHost) (void *opaque, int *status);
 
 int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
                              QEMUBalloonStatus *stat_func,
+                             QEMUBalloonTellHost *tellhost_func,
                              void *opaque, int balloon_pfn_shift);
 void qemu_remove_balloon_handler(void *opaque);
 bool qemu_balloon_is_inhibited(void);
@@ -30,5 +32,6 @@ void qemu_mutex_unlock_balloon_bitmap(void);
 void qemu_balloon_bitmap_update(ram_addr_t addr, int deflate);
 void qemu_balloon_bitmap_extend(RAMBlock *new_block,
                                 ram_addr_t old, ram_addr_t new);
+void qemu_balloon_bitmap_setup(void);
 
 #endif
diff --git a/migration/migration.c b/migration/migration.c
index 991313a..25678cc 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1200,6 +1200,15 @@ int migrate_use_xbzrle(void)
     return s->enabled_capabilities[MIGRATION_CAPABILITY_XBZRLE];
 }
 
+bool migrate_skip_balloon(void)
+{
+    MigrationState *s;
+
+    s = migrate_get_current();
+
+    return s->enabled_capabilities[MIGRATION_CAPABILITY_SKIP_BALLOON];
+}
+
 int64_t migrate_xbzrle_cache_size(void)
 {
     MigrationState *s;
diff --git a/migration/ram.c b/migration/ram.c
index 3f05738..a4c3582 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -41,6 +41,7 @@
 #include "trace.h"
 #include "exec/ram_addr.h"
 #include "qemu/rcu_queue.h"
+#include "sysemu/balloon.h"
 
 #ifdef DEBUG_MIGRATION_RAM
 #define DPRINTF(fmt, ...) \
@@ -1921,6 +1922,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
         acct_clear();
     }
 
+    qemu_balloon_bitmap_setup();
+
     /* For memory_global_dirty_log_start below.  */
     qemu_mutex_lock_iothread();
 
diff --git a/qapi-schema.json b/qapi-schema.json
index 54634c4..d2002c2 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -544,11 +544,14 @@
 #          been migrated, pulling the remaining pages along as needed. NOTE: If
 #          the migration fails during postcopy the VM will fail.  (since 2.6)
 #
+# @skip-balloon: Skip scanning ram pages released by virtio-balloon driver.
+#          (since 2.7)
+#
 # Since: 1.2
 ##
 { 'enum': 'MigrationCapability',
   'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks',
-           'compress', 'events', 'postcopy-ram'] }
+           'compress', 'events', 'postcopy-ram', 'skip-balloon'] }
 
 ##
 # @MigrationCapabilityStatus
