diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
index 5adaa97..db790f3 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
@@ -71,6 +71,7 @@ TERMINAL_DEV  mTerminalDevTemplate = {
   },
   NULL, // TerminalConsoleModeData
   0,  // SerialInTimeOut
+  DEFAULT_KEYBOARD_TIMER_INTERVAL, // KeyboardTimerInterval
 
   NULL, // RawFifo
   NULL, // UnicodeFiFo
@@ -984,10 +985,12 @@ TerminalDriverBindingStart (
                     );
     ASSERT_EFI_ERROR (Status);
 
+    TerminalDevice->KeyboardTimerInterval = GetKeyboardTimerInterval (Mode);
+
     Status = gBS->SetTimer (
                     TerminalDevice->TimerEvent,
                     TimerPeriodic,
-                    KEYBOARD_TIMER_INTERVAL
+                    TerminalDevice->KeyboardTimerInterval
                     );
     ASSERT_EFI_ERROR (Status);
 
diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
index 269d2ae..58d5664 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
@@ -68,7 +68,7 @@ typedef struct {
   UINTN   Rows;
 } TERMINAL_CONSOLE_MODE_DATA;
 
-#define KEYBOARD_TIMER_INTERVAL         200000  // 0.02s
+#define DEFAULT_KEYBOARD_TIMER_INTERVAL         200000  // 0.02s
 
 #define TERMINAL_DEV_SIGNATURE  SIGNATURE_32 ('t', 'm', 'n', 'l')
 
@@ -91,6 +91,7 @@ typedef struct {
   EFI_SIMPLE_TEXT_OUTPUT_MODE         SimpleTextOutputMode;
   TERMINAL_CONSOLE_MODE_DATA          *TerminalConsoleModeData;
   UINTN                               SerialInTimeOut;
+  UINT64                              KeyboardTimerInterval;
   RAW_DATA_FIFO                       *RawFiFo;
   UNICODE_FIFO                        *UnicodeFiFo;
   EFI_KEY_FIFO                        *EfiKeyFiFo;
@@ -1358,4 +1359,28 @@ TerminalConInTimerHandler (
   IN EFI_EVENT            Event,
   IN VOID                 *Context
   );
+
+/**
+  Calculate input polling timer interval by serial IO mode.
+
+  @param  Mode                  Pointer to serial IO mode.
+
+  @retval The required polling timer interval in 100ns.
+
+**/
+UINT64
+GetKeyboardTimerInterval (
+  IN EFI_SERIAL_IO_MODE   *Mode
+  );
+
+/**
+  Update period of polling timer event.
+
+  @param  TerminalDevice        The terminal device to update.
+**/
+VOID
+UpdatePollingRate (
+  IN TERMINAL_DEV         *TerminalDevice
+  );
+
 #endif
diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
index 2215df6..22349a0 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
@@ -502,6 +502,71 @@ TerminalConInWaitForKey (
 }
 
 /**
+  Calculate input polling timer interval by serial IO mode.
+
+  @param  Mode                  Pointer to serial IO mode.
+
+  @retval The required polling timer interval in 100ns.
+
+**/
+UINT64
+GetKeyboardTimerInterval (
+  IN EFI_SERIAL_IO_MODE *Mode
+  )
+{
+  UINT32                FifoDepth;
+
+  if (Mode->BaudRate == 0) {
+    return DEFAULT_KEYBOARD_TIMER_INTERVAL;
+  }
+
+  FifoDepth = Mode->ReceiveFifoDepth;
+  // Fix incorrect FIFO depth
+  if (FifoDepth == 0) {
+    FifoDepth = 1;
+  }
+
+  // We ignore stop bits and parity bit, and reduce the interval by 1/3,
+  // to make polling rate fast enough to avoid serial input truncation.
+  return DivU64x64Remainder (
+    FifoDepth * Mode->DataBits * 10000000 * 2,
+    Mode->BaudRate * 3,
+    NULL
+    );
+}
+
+
+/**
+  Update period of polling timer event.
+
+  @param  TerminalDevice        The terminal device to update.
+**/
+VOID
+UpdatePollingRate (
+  IN TERMINAL_DEV         *TerminalDevice
+  )
+{
+  UINT64                  NewInterval;
+  EFI_STATUS              Status;
+
+  NewInterval = GetKeyboardTimerInterval (TerminalDevice->SerialIo->Mode);
+
+  if (TerminalDevice->KeyboardTimerInterval == NewInterval) {
+    return;
+  }
+
+  Status = gBS->SetTimer (
+                  TerminalDevice->TimerEvent,
+                  TimerPeriodic,
+                  NewInterval
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  TerminalDevice->KeyboardTimerInterval = NewInterval;
+}
+
+
+/**
   Timer handler to poll the key from serial.
 
   @param  Event                    Indicates the event that invoke this function.
@@ -560,6 +625,9 @@ TerminalConInTimerHandler (
       TerminalDevice->SerialInTimeOut = SerialInTimeOut;
     }
   }
+
+  UpdatePollingRate (TerminalDevice);
+
   //
   // Check whether serial buffer is empty.
   // Skip the key transfer loop only if the SerialIo protocol instance
