diff --git a/qemu-timer.h b/qemu-timer.h
index 3f8880d..8f69467 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -24,6 +24,7 @@ void qemu_free_timer(QEMUTimer *ts);
 void qemu_del_timer(QEMUTimer *ts);
 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
 int qemu_timer_pending(QEMUTimer *ts);
+int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
 
 extern int64_t ticks_per_sec;
 
diff --git a/vl.c b/vl.c
index 60a00e1..802c3fb 100644
--- a/vl.c
+++ b/vl.c
@@ -1207,7 +1207,7 @@ int qemu_timer_pending(QEMUTimer *ts)
     return 0;
 }
 
-static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
+int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
 {
     if (!timer_head)
         return 0;
diff --git a/vnc.c b/vnc.c
index ce5e0cc..5ccc0a3 100644
--- a/vnc.c
+++ b/vnc.c
@@ -30,7 +30,9 @@
 #include "qemu-timer.h"
 #include "acl.h"
 
-#define VNC_REFRESH_INTERVAL (1000 / 30)
+#define VNC_REFRESH_INTERVAL_BASE 30
+#define VNC_REFRESH_INTERVAL_INC  50
+#define VNC_REFRESH_INTERVAL_MAX  2000
 
 #include "vnc_keysym.h"
 #include "d3des.h"
@@ -215,7 +217,7 @@ static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
    3) resolutions > 1024
 */
 
-static void vnc_update_client(VncState *vs, int has_dirty);
+static int vnc_update_client(VncState *vs, int has_dirty);
 static void vnc_disconnect_start(VncState *vs);
 static void vnc_disconnect_finish(VncState *vs);
 static void vnc_init_timer(VncDisplay *vd);
@@ -751,7 +753,7 @@ static int find_and_clear_dirty_height(struct VncState *vs,
     return h;
 }
 
-static void vnc_update_client(VncState *vs, int has_dirty)
+static int vnc_update_client(VncState *vs, int has_dirty)
 {
     if (vs->need_update && vs->csock != -1) {
         VncDisplay *vd = vs->vd;
@@ -761,10 +763,10 @@ static void vnc_update_client(VncState *vs, int has_dirty)
 
         if (vs->output.offset && !vs->audio_cap && !vs->force_update)
             /* kernel send buffers are full -> drop frames to throttle */
-            return;
+            return 0;
 
         if (!has_dirty && !vs->audio_cap && !vs->force_update)
-            return;
+            return 0;
 
         /*
          * Send screen updates to the vnc client using the server
@@ -806,11 +808,13 @@ static void vnc_update_client(VncState *vs, int has_dirty)
         vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
         vnc_flush(vs);
         vs->force_update = 0;
-
+        return n_rectangles;
     }
 
     if (vs->csock == -1)
         vnc_disconnect_finish(vs);
+
+    return 0;
 }
 
 /* audio */
@@ -1701,6 +1705,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
 {
     int i;
     uint16_t limit;
+    VncDisplay *vd = vs->vd;
+
+    if (data[0] > 3) {
+        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+        if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
+            qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
+    }
 
     switch (data[0]) {
     case 0:
@@ -2104,7 +2115,7 @@ static void vnc_refresh(void *opaque)
 {
     VncDisplay *vd = opaque;
     VncState *vs = NULL;
-    int has_dirty = 0;
+    int has_dirty = 0, rects = 0;
 
     vga_hw_update();
 
@@ -2112,15 +2123,25 @@ static void vnc_refresh(void *opaque)
 
     vs = vd->clients;
     while (vs != NULL) {
-        vnc_update_client(vs, has_dirty);
+        rects += vnc_update_client(vs, has_dirty);
         vs = vs->next;
     }
 
-    qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+    if (has_dirty && rects) {
+        vd->timer_interval /= 2;
+        if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
+            vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+    } else {
+        vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
+        if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
+            vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
+    }
+    qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
 }
 
 static void vnc_init_timer(VncDisplay *vd)
 {
+    vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
     if (vd->timer == NULL && vd->clients != NULL) {
         vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
         vnc_refresh(vd);
diff --git a/vnc.h b/vnc.h
index 5c903de..fcc6824 100644
--- a/vnc.h
+++ b/vnc.h
@@ -93,6 +93,7 @@ struct VncSurface
 struct VncDisplay
 {
     QEMUTimer *timer;
+    int timer_interval;
     int lsock;
     DisplayState *ds;
     VncState *clients;
