diff --git a/src/caps.c b/src/caps.c
index e6c235c..7ace1ad 100644
--- a/src/caps.c
+++ b/src/caps.c
@@ -190,6 +190,8 @@ const char _vte_xterm_capability_strings[] =
         ENTRY(CSI "?%dn", "dec-device-status-report")
         ENTRY(CSI "!p", "soft-reset")
         ENTRY(CSI "%d;%d\"p", "set-conformance-level")
+        ENTRY(CSI " q", "set-cursor-style")
+        ENTRY(CSI "%d q", "set-cursor-style")
         ENTRY(CSI "%d\"q", "select-character-protection")
 
         ENTRY(CSI "r", "set-scrolling-region")
diff --git a/src/vte-private.h b/src/vte-private.h
index 1eb86a6..ca10c2e 100644
--- a/src/vte-private.h
+++ b/src/vte-private.h
@@ -165,6 +165,29 @@ typedef struct _VtePaletteColor {
 	} sources[2];
 } VtePaletteColor;
 
+/* These correspond to the parameters for DECSCUSR (Set cursor style). */
+typedef enum _VteCursorStyle {
+        /* We treat 0 and 1 differently, assuming that the VT510 does so too.
+         *
+         * See, according to the "VT510 Video Terminal Programmer Information",
+         * from vt100.net, paragraph "2.5.7 Cursor Display", there was a menu
+         * item in the "Terminal Set-Up" to set the cursor's style. It looks
+         * like that defaulted to blinking block. So it makes sense for 0 to
+         * mean "set cursor style to default (set by Set-Up)" and 1 to mean
+         * "set cursor style to blinking block", since that default need not be
+         * blinking block. Access to a VT510 is needed to test this theory,
+         * but it seems plausible. And, anyhow, we can even decide we know
+         * better than the VT510 designers! */
+        VTE_CURSOR_STYLE_TERMINAL_DEFAULT = 0,
+        VTE_CURSOR_STYLE_BLINK_BLOCK      = 1,
+        VTE_CURSOR_STYLE_STEADY_BLOCK     = 2,
+        VTE_CURSOR_STYLE_BLINK_UNDERLINE  = 3,
+        VTE_CURSOR_STYLE_STEADY_UNDERLINE = 4,
+        /* *_IBEAM are xterm extensions */
+        VTE_CURSOR_STYLE_BLINK_IBEAM      = 5,
+        VTE_CURSOR_STYLE_STEADY_IBEAM     = 6
+} VteCursorStyle;
+
 /* Terminal private data. */
 struct _VteTerminalPrivate {
         /* Metric and sizing data: dimensions of the window */
@@ -286,11 +309,11 @@ struct _VteTerminalPrivate {
 	gboolean alternate_screen_scroll;
 	long scrollback_lines;
 
-	/* Cursor shape */
+	/* Cursor shape, as set via API */
 	VteCursorShape cursor_shape;
         float cursor_aspect_ratio;
 
-	/* Cursor blinking. */
+	/* Cursor blinking, as set in dconf. */
         VteCursorBlinkMode cursor_blink_mode;
 	gboolean cursor_blink_state;
 	guint cursor_blink_tag;           /* cursor blinking timeout ID */
@@ -301,6 +324,10 @@ struct _VteTerminalPrivate {
 	gboolean cursor_visible;
 	gboolean has_focus;               /* is the terminal window focused */
 
+        /* DECSCUSR cursor style (shape and blinking possibly overridden
+         * via escape sequence) */
+        VteCursorStyle cursor_style;
+
 	/* Input device options. */
         gboolean input_enabled;
 	time_t last_keypress_time;
@@ -450,6 +477,8 @@ VteRowData *_vte_terminal_ring_insert (VteTerminal *terminal, glong position, gb
 VteRowData *_vte_terminal_ring_append (VteTerminal *terminal, gboolean fill);
 void _vte_terminal_ring_remove (VteTerminal *terminal, glong position);
 
+void _vte_terminal_set_cursor_style(VteTerminal *terminal, VteCursorStyle style);
+
 /* vteseq.c: */
 void _vte_terminal_handle_sequence(VteTerminal *terminal,
 				   const char *match,
diff --git a/src/vte.c b/src/vte.c
index aca4195..a018cd1 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -132,8 +132,10 @@ static void vte_terminal_add_process_timeout (VteTerminal *terminal);
 static void add_update_timeout (VteTerminal *terminal);
 static void remove_update_timeout (VteTerminal *terminal);
 static void reset_update_regions (VteTerminal *terminal);
-static void vte_terminal_set_cursor_blinks_internal(VteTerminal *terminal, gboolean blink);
+static void vte_terminal_update_cursor_blinks_internal(VteTerminal *terminal);
 static void _vte_check_cursor_blink(VteTerminal *terminal);
+static VteCursorShape _vte_terminal_decscusr_cursor_shape(VteTerminal *terminal);
+static VteCursorBlinkMode _vte_terminal_decscusr_cursor_blink(VteTerminal *terminal);
 
 static gboolean process_timeout (gpointer data);
 static gboolean update_timeout (gpointer data);
@@ -8029,6 +8031,10 @@ vte_terminal_init(VteTerminal *terminal)
         pvt->cursor_blinks = FALSE;
         pvt->cursor_blink_mode = VTE_CURSOR_BLINK_SYSTEM;
 
+        /* DECSCUSR cursor style (shape and blinking possibly overridden
+         * via escape sequence) */
+        pvt->cursor_style = VTE_CURSOR_STYLE_TERMINAL_DEFAULT;
+
 	/* Matching data. */
 	pvt->match_regexes = g_array_new(FALSE, TRUE,
 					 sizeof(struct vte_match_regex));
@@ -8291,8 +8297,7 @@ vte_terminal_sync_settings (GtkSettings *settings,
         pvt->cursor_blink_cycle = blink_time / 2;
         pvt->cursor_blink_timeout = blink_timeout;
 
-        if (pvt->cursor_blink_mode == VTE_CURSOR_BLINK_SYSTEM)
-                vte_terminal_set_cursor_blinks_internal(terminal, blink);
+        vte_terminal_update_cursor_blinks_internal(terminal);
 }
 
 static void
@@ -9555,7 +9560,7 @@ vte_terminal_paint_cursor(VteTerminal *terminal)
 	x = item.x;
 	y = item.y;
 
-	switch (terminal->pvt->cursor_shape) {
+        switch (_vte_terminal_decscusr_cursor_shape(terminal)) {
 
 		case VTE_CURSOR_SHAPE_IBEAM: {
                         int stem_width;
@@ -11330,11 +11335,25 @@ vte_terminal_get_has_selection(VteTerminal *terminal)
 }
 
 static void
-vte_terminal_set_cursor_blinks_internal(VteTerminal *terminal, gboolean blink)
+vte_terminal_update_cursor_blinks_internal(VteTerminal *terminal)
 {
         VteTerminalPrivate *pvt = terminal->pvt;
+        gboolean blink = FALSE;
+
+        switch (_vte_terminal_decscusr_cursor_blink(terminal)) {
+        case VTE_CURSOR_BLINK_SYSTEM:
+                g_object_get(gtk_widget_get_settings(GTK_WIDGET(terminal)),
+                                                     "gtk-cursor-blink",
+                                                     &blink, NULL);
+                break;
+        case VTE_CURSOR_BLINK_ON:
+                blink = TRUE;
+                break;
+        case VTE_CURSOR_BLINK_OFF:
+                blink = FALSE;
+                break;
+        }
 
-	blink = !!blink;
 	if (pvt->cursor_blinks == blink)
 		return;
 
@@ -11354,7 +11373,6 @@ void
 vte_terminal_set_cursor_blink_mode(VteTerminal *terminal, VteCursorBlinkMode mode)
 {
         VteTerminalPrivate *pvt;
-        gboolean blinks;
 
 	g_return_if_fail(VTE_IS_TERMINAL(terminal));
         pvt = terminal->pvt;
@@ -11364,21 +11382,7 @@ vte_terminal_set_cursor_blink_mode(VteTerminal *terminal, VteCursorBlinkMode mod
 
         pvt->cursor_blink_mode = mode;
 
-        switch (mode) {
-          case VTE_CURSOR_BLINK_SYSTEM:
-            g_object_get(gtk_widget_get_settings(GTK_WIDGET(terminal)),
-                                                 "gtk-cursor-blink", &blinks,
-                                                 NULL);
-            break;
-          case VTE_CURSOR_BLINK_ON:
-            blinks = TRUE;
-            break;
-          case VTE_CURSOR_BLINK_OFF:
-            blinks = FALSE;
-            break;
-        }
-
-        vte_terminal_set_cursor_blinks_internal(terminal, blinks);
+        vte_terminal_update_cursor_blinks_internal(terminal);
 
         g_object_notify(G_OBJECT(terminal), "cursor-blink-mode");
 }
@@ -11439,6 +11443,83 @@ vte_terminal_get_cursor_shape(VteTerminal *terminal)
         return terminal->pvt->cursor_shape;
 }
 
+/* DECSCUSR set cursor style */
+void
+_vte_terminal_set_cursor_style(VteTerminal *terminal, VteCursorStyle style)
+{
+        VteTerminalPrivate *pvt;
+
+        g_return_if_fail(VTE_IS_TERMINAL(terminal));
+        pvt = terminal->pvt;
+
+        if (pvt->cursor_style == style)
+                return;
+
+        pvt->cursor_style = style;
+
+        vte_terminal_update_cursor_blinks_internal(terminal);
+
+        /* and this will also make cursor shape match the DECSCUSR style */
+        _vte_invalidate_cursor_once(terminal, FALSE);
+}
+
+/*
+ * _vte_terminal_decscusr_cursor_blink:
+ * @terminal: a #VteTerminal
+ *
+ * Returns the cursor blink mode set by DECSCUSR. If DECSCUSR was never
+ * called, or it set the blink mode to terminal default, this returns the
+ * value set via API or in dconf. Internal use only.
+ *
+ * Return value: cursor blink mode
+ */
+static VteCursorBlinkMode
+_vte_terminal_decscusr_cursor_blink(VteTerminal *terminal)
+{
+        switch (terminal->pvt->cursor_style) {
+        default:
+        case VTE_CURSOR_STYLE_TERMINAL_DEFAULT:
+                return terminal->pvt->cursor_blink_mode;
+        case VTE_CURSOR_STYLE_BLINK_BLOCK:
+        case VTE_CURSOR_STYLE_BLINK_UNDERLINE:
+        case VTE_CURSOR_STYLE_BLINK_IBEAM:
+                return VTE_CURSOR_BLINK_ON;
+        case VTE_CURSOR_STYLE_STEADY_BLOCK:
+        case VTE_CURSOR_STYLE_STEADY_UNDERLINE:
+        case VTE_CURSOR_STYLE_STEADY_IBEAM:
+                return VTE_CURSOR_BLINK_OFF;
+        }
+}
+
+/*
+ * _vte_terminal_decscusr_cursor_shape:
+ * @terminal: a #VteTerminal
+ *
+ * Returns the cursor shape set by DECSCUSR. If DECSCUSR was never called,
+ * or it set the cursor shape to terminal default, this returns the value
+ * set via API. Internal use only.
+ *
+ * Return value: cursor shape
+ */
+static VteCursorShape
+_vte_terminal_decscusr_cursor_shape(VteTerminal *terminal)
+{
+        switch (terminal->pvt->cursor_style) {
+        default:
+        case VTE_CURSOR_STYLE_TERMINAL_DEFAULT:
+                return terminal->pvt->cursor_shape;
+        case VTE_CURSOR_STYLE_BLINK_BLOCK:
+        case VTE_CURSOR_STYLE_STEADY_BLOCK:
+                return VTE_CURSOR_SHAPE_BLOCK;
+        case VTE_CURSOR_STYLE_BLINK_UNDERLINE:
+        case VTE_CURSOR_STYLE_STEADY_UNDERLINE:
+                return VTE_CURSOR_SHAPE_UNDERLINE;
+        case VTE_CURSOR_STYLE_BLINK_IBEAM:
+        case VTE_CURSOR_STYLE_STEADY_IBEAM:
+                return VTE_CURSOR_SHAPE_IBEAM;
+        }
+}
+
 /**
  * vte_terminal_set_scrollback_lines:
  * @terminal: a #VteTerminal
@@ -11715,6 +11796,8 @@ vte_terminal_reset(VteTerminal *terminal,
                 vte_terminal_queue_adjustment_value_changed (terminal, 0);
 		_vte_terminal_adjust_adjustments_full (terminal);
 	}
+        /* DECSCUSR cursor style */
+        pvt->cursor_style = VTE_CURSOR_STYLE_TERMINAL_DEFAULT;
 	/* Do more stuff we refer to as a "full" reset. */
 	if (clear_tabstops) {
 		vte_terminal_set_default_tabstops(terminal);
diff --git a/src/vteseq-n.gperf b/src/vteseq-n.gperf
index 208ab19..424a05d 100644
--- a/src/vteseq-n.gperf
+++ b/src/vteseq-n.gperf
@@ -75,6 +75,7 @@ struct vteseq_n_struct {
 "erase-characters", VTE_SEQUENCE_HANDLER(vte_sequence_handler_erase_characters)
 "erase-in-display", VTE_SEQUENCE_HANDLER(vte_sequence_handler_erase_in_display)
 "set-window-title", VTE_SEQUENCE_HANDLER(vte_sequence_handler_set_window_title)
+"set-cursor-style", VTE_SEQUENCE_HANDLER(vte_sequence_handler_set_cursor_style)
 #"cursor-lower-left", VTE_SEQUENCE_HANDLER_NULL
 "delete-characters", VTE_SEQUENCE_HANDLER(vte_sequence_handler_delete_characters)
 "application-keypad", VTE_SEQUENCE_HANDLER(vte_sequence_handler_application_keypad)
diff --git a/src/vteseq.c b/src/vteseq.c
index 4d21f9f..a5726e3 100644
--- a/src/vteseq.c
+++ b/src/vteseq.c
@@ -2787,6 +2787,34 @@ vte_sequence_handler_screen_alignment_test (VteTerminal *terminal, GValueArray *
 	terminal->pvt->text_modified_flag = TRUE;
 }
 
+/* DECSCUSR set cursor style */
+static void
+vte_sequence_handler_set_cursor_style (VteTerminal *terminal, GValueArray *params)
+{
+        long style;
+
+        if ((params == NULL) || (params->n_values > 1)) {
+                return;
+        }
+
+        if (params->n_values == 0) {
+                /* no parameters means default (according to vt100.net) */
+                style = VTE_CURSOR_STYLE_TERMINAL_DEFAULT;
+        } else {
+                GValue *value = g_value_array_get_nth(params, 0);
+
+                if (!G_VALUE_HOLDS_LONG(value)) {
+                        return;
+                }
+                style = g_value_get_long(value);
+                if (style < 0 || style > 6) {
+                        return;
+                }
+        }
+
+        _vte_terminal_set_cursor_style(terminal, style);
+}
+
 /* Perform a soft reset. */
 static void
 vte_sequence_handler_soft_reset (VteTerminal *terminal, GValueArray *params)
