diff --git a/src/terminal/terminaldisplay.cc b/src/terminal/terminaldisplay.cc
index c44952857..b3af91b72 100644
--- a/src/terminal/terminaldisplay.cc
+++ b/src/terminal/terminaldisplay.cc
@@ -142,6 +142,12 @@ std::string Display::new_frame( bool initialized, const Framebuffer& last, const
     frame.append( "\033[?25l" );
   }
 
+  /* is cursor style initialized? */
+  if ( !initialized ) {
+    frame.cursor_style = Terminal::CursorStyle::BLINKING_BLOCK;
+    frame.append( "\033[0 q" );
+  }
+
   int frame_y = 0;
   Framebuffer::row_pointer blank_row;
   Framebuffer::rows_type rows( frame.last_frame.get_rows() );
@@ -267,6 +273,13 @@ std::string Display::new_frame( bool initialized, const Framebuffer& last, const
     }
   }
 
+  /* has cursor style changed? */
+  if ( ( !initialized ) || ( f.ds.cursor_style != frame.cursor_style ) ) {
+    char cursor_style_sequence_buf[6];
+    snprintf( cursor_style_sequence_buf, sizeof cursor_style_sequence_buf, "\033[%d q", f.ds.cursor_style );
+    frame.append( cursor_style_sequence_buf );
+  }
+
   /* have renditions changed? */
   frame.update_rendition( f.ds.get_renditions(), !initialized );
 
@@ -460,7 +473,7 @@ bool Display::put_row( bool initialized,
 
 FrameState::FrameState( const Framebuffer& s_last )
   : str(), cursor_x( 0 ), cursor_y( 0 ), current_rendition( 0 ), cursor_visible( s_last.ds.cursor_visible ),
-    last_frame( s_last )
+    cursor_style( s_last.ds.cursor_style ), last_frame( s_last )
 {
   /* Preallocate for better performance.  Make a guess-- doesn't matter for correctness */
   str.reserve( last_frame.ds.get_width() * last_frame.ds.get_height() * 4 );
diff --git a/src/terminal/terminaldisplay.h b/src/terminal/terminaldisplay.h
index bd900e8fa..3378b848c 100644
--- a/src/terminal/terminaldisplay.h
+++ b/src/terminal/terminaldisplay.h
@@ -45,6 +45,7 @@ class FrameState
   int cursor_x, cursor_y;
   Renditions current_rendition;
   bool cursor_visible;
+  int cursor_style;
 
   const Framebuffer& last_frame;
 
diff --git a/src/terminal/terminalframebuffer.cc b/src/terminal/terminalframebuffer.cc
index 5d3a1bc07..06bb6f1d9 100644
--- a/src/terminal/terminalframebuffer.cc
+++ b/src/terminal/terminalframebuffer.cc
@@ -62,10 +62,11 @@ void DrawState::reinitialize_tabs( unsigned int start )
 DrawState::DrawState( int s_width, int s_height )
   : width( s_width ), height( s_height ), cursor_col( 0 ), cursor_row( 0 ), combining_char_col( 0 ),
     combining_char_row( 0 ), default_tabs( true ), tabs( s_width ), scrolling_region_top_row( 0 ),
-    scrolling_region_bottom_row( height - 1 ), renditions( 0 ), save(), next_print_will_wrap( false ),
-    origin_mode( false ), auto_wrap_mode( true ), insert_mode( false ), cursor_visible( true ),
-    reverse_video( false ), bracketed_paste( false ), mouse_reporting_mode( MOUSE_REPORTING_NONE ),
-    mouse_focus_event( false ), mouse_alternate_scroll( false ), mouse_encoding_mode( MOUSE_ENCODING_DEFAULT ),
+    scrolling_region_bottom_row( height - 1 ), renditions( 0 ), save(),
+    cursor_style( Terminal::CursorStyle::BLINKING_BLOCK ), next_print_will_wrap( false ), origin_mode( false ),
+    auto_wrap_mode( true ), insert_mode( false ), cursor_visible( true ), reverse_video( false ),
+    bracketed_paste( false ), mouse_reporting_mode( MOUSE_REPORTING_NONE ), mouse_focus_event( false ),
+    mouse_alternate_scroll( false ), mouse_encoding_mode( MOUSE_ENCODING_DEFAULT ),
     application_mode_cursor_keys( false )
 {
   reinitialize_tabs( 0 );
@@ -387,6 +388,7 @@ void Framebuffer::soft_reset( void )
   ds.insert_mode = false;
   ds.origin_mode = false;
   ds.cursor_visible = true; /* per xterm and gnome-terminal */
+  ds.cursor_style = Terminal::CursorStyle::BLINKING_BLOCK;
   ds.application_mode_cursor_keys = false;
   ds.set_scrolling_region( 0, ds.get_height() - 1 );
   ds.add_rendition( 0 );
diff --git a/src/terminal/terminalframebuffer.h b/src/terminal/terminalframebuffer.h
index 9039d4e7f..5000ff651 100644
--- a/src/terminal/terminalframebuffer.h
+++ b/src/terminal/terminalframebuffer.h
@@ -45,8 +45,21 @@
 /* Terminal framebuffer */
 
 namespace Terminal {
+using std::make_shared;
+using std::shared_ptr;
 using color_type = uint32_t;
 
+enum CursorStyle
+{
+  BLINKING_BLOCK = 0,
+  BLINKING_BLOCK_DEFAULT = 1,
+  STEADY_BLOCK = 2,
+  BLINKING_UNDERLINE = 3,
+  STEADY_UNDERLINE = 4,
+  BLINKING_BAR = 5,
+  STEADY_BAR = 6,
+};
+
 class Renditions
 {
 public:
@@ -275,6 +288,7 @@ class DrawState
   SavedCursor save;
 
 public:
+  int cursor_style;
   bool next_print_will_wrap;
   bool origin_mode;
   bool auto_wrap_mode;
@@ -353,8 +367,9 @@ class DrawState
     return ( width == x.width ) && ( height == x.height ) && ( cursor_col == x.cursor_col )
            && ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible )
            && ( reverse_video == x.reverse_video ) && ( renditions == x.renditions )
-           && ( bracketed_paste == x.bracketed_paste ) && ( mouse_reporting_mode == x.mouse_reporting_mode )
-           && ( mouse_focus_event == x.mouse_focus_event ) && ( mouse_alternate_scroll == x.mouse_alternate_scroll )
+           && ( cursor_style == x.cursor_style ) && ( bracketed_paste == x.bracketed_paste )
+           && ( mouse_reporting_mode == x.mouse_reporting_mode ) && ( mouse_focus_event == x.mouse_focus_event )
+           && ( mouse_alternate_scroll == x.mouse_alternate_scroll )
            && ( mouse_encoding_mode == x.mouse_encoding_mode );
   }
 };
diff --git a/src/terminal/terminalfunctions.cc b/src/terminal/terminalfunctions.cc
index 40c41afc4..000b4d401 100644
--- a/src/terminal/terminalfunctions.cc
+++ b/src/terminal/terminalfunctions.cc
@@ -51,6 +51,27 @@ static void clearline( Framebuffer* fb, int row, int start, int end )
   }
 }
 
+/* cursor style */
+static void CSI_DECSCUSR( Framebuffer* fb, Dispatcher* dispatch )
+{
+  int style = dispatch->getparam( 0, 0 );
+  switch ( style ) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+      fb->ds.cursor_style = style;
+      break;
+    default:
+      break;
+  }
+}
+
+static Function func_CSI_DECSCUSR( CSI, " q", CSI_DECSCUSR );
+
 /* erase in line */
 static void CSI_EL( Framebuffer* fb, Dispatcher* dispatch )
 {