diff --git a/common/jobs/job_export_pcb_pdf.cpp b/common/jobs/job_export_pcb_pdf.cpp
index c62e622e78..7f2a5f39fb 100644
--- a/common/jobs/job_export_pcb_pdf.cpp
+++ b/common/jobs/job_export_pcb_pdf.cpp
@@ -34,6 +34,7 @@ JOB_EXPORT_PCB_PDF::JOB_EXPORT_PCB_PDF( bool aIsCli ) :
         m_plotRefDes( true ),
         m_plotBorderTitleBlocks( false ),
         m_printMaskLayer(),
+        m_sketchPadsOnFabLayers( false ),
         m_drillShapeOption( 2 )
 {
 }
\ No newline at end of file
diff --git a/common/jobs/job_export_pcb_pdf.h b/common/jobs/job_export_pcb_pdf.h
index 339d9d8ae2..72314368ef 100644
--- a/common/jobs/job_export_pcb_pdf.h
+++ b/common/jobs/job_export_pcb_pdf.h
@@ -46,9 +46,10 @@ public:
 
     LSEQ m_printMaskLayer;
 
+    bool m_sketchPadsOnFabLayers;
+
     // How holes in pads/vias are plotted:
     // 0 = no hole, 1 = small shape, 2 = actual shape
-    // Not used in some plotters (Gerber)
     int m_drillShapeOption;
 };
 
diff --git a/common/jobs/job_export_pcb_svg.cpp b/common/jobs/job_export_pcb_svg.cpp
index 081891e3cc..63efcb8881 100644
--- a/common/jobs/job_export_pcb_svg.cpp
+++ b/common/jobs/job_export_pcb_svg.cpp
@@ -33,6 +33,7 @@ JOB_EXPORT_PCB_SVG::JOB_EXPORT_PCB_SVG( bool aIsCli ) :
     m_plotDrawingSheet( true ),
     m_pageSizeMode( 0 ),
     m_printMaskLayer(),
+    m_sketchPadsOnFabLayers( false ),
     m_drillShapeOption( 2 )
 {
 }
\ No newline at end of file
diff --git a/common/jobs/job_export_pcb_svg.h b/common/jobs/job_export_pcb_svg.h
index bc11f821fc..96821ab4ce 100644
--- a/common/jobs/job_export_pcb_svg.h
+++ b/common/jobs/job_export_pcb_svg.h
@@ -44,10 +44,10 @@ public:
     int m_pageSizeMode;
 
     LSEQ m_printMaskLayer;
+    bool m_sketchPadsOnFabLayers;
 
     // How holes in pads/vias are plotted:
     // 0 = no hole, 1 = small shape, 2 = actual shape
-    // Not used in some plotters (Gerber)
     int m_drillShapeOption;
 };
 
diff --git a/common/jobs/job_fp_export_svg.cpp b/common/jobs/job_fp_export_svg.cpp
index 45e496caa8..2bb0d00b43 100644
--- a/common/jobs/job_fp_export_svg.cpp
+++ b/common/jobs/job_fp_export_svg.cpp
@@ -26,6 +26,7 @@ JOB_FP_EXPORT_SVG::JOB_FP_EXPORT_SVG( bool aIsCli ) :
     m_libraryPath(),
     m_footprint(),
     m_outputDirectory(),
-    m_blackAndWhite( false )
+    m_blackAndWhite( false ),
+    m_sketchPadsOnFabLayers( false )
 {
 }
\ No newline at end of file
diff --git a/common/jobs/job_fp_export_svg.h b/common/jobs/job_fp_export_svg.h
index 7a58cbd5da..5c8da5d15d 100644
--- a/common/jobs/job_fp_export_svg.h
+++ b/common/jobs/job_fp_export_svg.h
@@ -39,6 +39,7 @@ public:
     wxString m_colorTheme;
 
     bool m_blackAndWhite;
+    bool m_sketchPadsOnFabLayers;
     LSEQ m_printMaskLayer;
 };
 
diff --git a/common/pcb_plot_params.keywords b/common/pcb_plot_params.keywords
index 5ac42d1fe4..bb20738e21 100644
--- a/common/pcb_plot_params.keywords
+++ b/common/pcb_plot_params.keywords
@@ -28,6 +28,7 @@ pdf_metadata
 plotframeref
 plotfptext
 plotinvisibletext
+plotpadnumbers
 plotreference
 plotvalue
 psa4output
diff --git a/include/plotters/plotter.h b/include/plotters/plotter.h
index 9ad64317f5..d32b5c53b7 100644
--- a/include/plotters/plotter.h
+++ b/include/plotters/plotter.h
@@ -34,6 +34,7 @@
 #include <gal/color4d.h>
 #include <stroke_params.h>
 #include <render_settings.h>
+#include <font/font.h>
 
 
 class COLOR_SETTINGS;
@@ -441,8 +442,8 @@ public:
                            const COLOR4D&         aColor,
                            const wxString&        aText,
                            const TEXT_ATTRIBUTES& aAttributes,
-                           KIFONT::FONT*          aFont,
-                           const KIFONT::METRICS& aFontMetrics,
+                           KIFONT::FONT*          aFont = nullptr,
+                           const KIFONT::METRICS& aFontMetrics = KIFONT::METRICS::Default(),
                            void*                  aData = nullptr );
     /**
      * Create a clickable hyperlink with a rectangular click area
diff --git a/kicad/cli/command_fp_export_svg.cpp b/kicad/cli/command_fp_export_svg.cpp
index 816b3ece6c..c8f45100c1 100644
--- a/kicad/cli/command_fp_export_svg.cpp
+++ b/kicad/cli/command_fp_export_svg.cpp
@@ -50,6 +50,10 @@ CLI::FP_EXPORT_SVG_COMMAND::FP_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND( "
             .help( UTF8STDSTR( _( "Specific footprint to export within the library" ) ) )
             .metavar( "FOOTPRINT_NAME" );
 
+    m_argParser.add_argument( "--sp", ARG_SKETCH_PADS_ON_FAB_LAYERS )
+            .help( UTF8STDSTR( _( ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC ) ) )
+            .flag();
+
     m_argParser.add_argument( ARG_BLACKANDWHITE )
             .help( UTF8STDSTR( _( ARG_BLACKANDWHITE_DESC ) ) )
             .flag();
@@ -67,6 +71,7 @@ int CLI::FP_EXPORT_SVG_COMMAND::doPerform( KIWAY& aKiway )
     svgJob->m_libraryPath = m_argInput;
     svgJob->m_outputDirectory = m_argOutput;
     svgJob->m_blackAndWhite = m_argParser.get<bool>( ARG_BLACKANDWHITE );
+    svgJob->m_sketchPadsOnFabLayers = m_argParser.get<bool>( ARG_SKETCH_PADS_ON_FAB_LAYERS );
     svgJob->m_footprint = From_UTF8( m_argParser.get<std::string>( ARG_FOOTPRINT ).c_str() );
     svgJob->SetVarOverrides( m_argDefineVars );
 
diff --git a/kicad/cli/command_pcb_export_base.h b/kicad/cli/command_pcb_export_base.h
index 19fd117a37..3c05c900e2 100644
--- a/kicad/cli/command_pcb_export_base.h
+++ b/kicad/cli/command_pcb_export_base.h
@@ -29,6 +29,12 @@ namespace CLI
 #define ARG_BLACKANDWHITE "--black-and-white"
 #define ARG_BLACKANDWHITE_DESC "Black and white only"
 
+#define ARG_SKETCH_PADS_ON_FAB_LAYERS "--sketch-pads-on-fab-layers"
+#define ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC "Draw pad outlines and their numbers on front and back fab layers"
+
+#define ARG_DRILL_SHAPE_OPTION "--drill-shape-opt"
+#define ARG_DRILL_SHAPE_OPTION_DESC "Set pad/via drill shape option (0 = no shape, 1 = small shape, 2 = actual shape)"
+
 #define ARG_NEGATIVE "--negative"
 #define ARG_NEGATIVE_SHORT "-n"
 #define ARG_NEGATIVE_DESC "Plot as negative (useful for directly etching from the export)"
diff --git a/kicad/cli/command_pcb_export_pdf.cpp b/kicad/cli/command_pcb_export_pdf.cpp
index 7d8a9a8afd..b105703c65 100644
--- a/kicad/cli/command_pcb_export_pdf.cpp
+++ b/kicad/cli/command_pcb_export_pdf.cpp
@@ -26,13 +26,8 @@
 #include <string_utils.h>
 #include <wx/crt.h>
 
-#include <macros.h>
-#include <wx/tokenzr.h>
-
 #include <locale_io.h>
 
-#define ARG_DRILL_SHAPE_OPTION "--drill-shape-opt"
-
 
 CLI::PCB_EXPORT_PDF_COMMAND::PCB_EXPORT_PDF_COMMAND() : PCB_EXPORT_BASE_COMMAND( "pdf" )
 {
@@ -58,6 +53,10 @@ CLI::PCB_EXPORT_PDF_COMMAND::PCB_EXPORT_PDF_COMMAND() : PCB_EXPORT_BASE_COMMAND(
             .help( UTF8STDSTR( _( "Include the border and title block" ) ) )
             .flag();
 
+    m_argParser.add_argument( "--sp", ARG_SKETCH_PADS_ON_FAB_LAYERS )
+            .help( UTF8STDSTR( _( ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC ) ) )
+            .flag();
+
     m_argParser.add_argument( ARG_NEGATIVE_SHORT, ARG_NEGATIVE )
             .help( UTF8STDSTR( _( ARG_NEGATIVE_DESC ) ) )
             .flag();
@@ -72,8 +71,7 @@ CLI::PCB_EXPORT_PDF_COMMAND::PCB_EXPORT_PDF_COMMAND() : PCB_EXPORT_BASE_COMMAND(
             .metavar( "THEME_NAME" );
 
     m_argParser.add_argument( ARG_DRILL_SHAPE_OPTION )
-            .help( UTF8STDSTR( _( "Set pad/via drill shape option (0 = no shape, 1 = "
-                                  "small shape, 2 = actual shape)" ) ) )
+            .help( UTF8STDSTR( _( ARG_DRILL_SHAPE_OPTION_DESC ) ) )
             .scan<'i', int>()
             .default_value( 2 );
 }
@@ -109,6 +107,7 @@ int CLI::PCB_EXPORT_PDF_COMMAND::doPerform( KIWAY& aKiway )
     pdfJob->m_colorTheme = From_UTF8( m_argParser.get<std::string>( ARG_THEME ).c_str() );
     pdfJob->m_negative = m_argParser.get<bool>( ARG_NEGATIVE );
 
+    pdfJob->m_sketchPadsOnFabLayers = m_argParser.get<bool>( ARG_SKETCH_PADS_ON_FAB_LAYERS );
     pdfJob->m_drillShapeOption = m_argParser.get<int>( ARG_DRILL_SHAPE_OPTION );
 
     pdfJob->m_printMaskLayer = m_selectedLayers;
diff --git a/kicad/cli/command_pcb_export_svg.cpp b/kicad/cli/command_pcb_export_svg.cpp
index 1ac5dc005c..ddc52278d6 100644
--- a/kicad/cli/command_pcb_export_svg.cpp
+++ b/kicad/cli/command_pcb_export_svg.cpp
@@ -29,12 +29,9 @@
 #include <regex>
 #include <wx/crt.h>
 
-#include <macros.h>
-#include <wx/tokenzr.h>
 
 #define ARG_EXCLUDE_DRAWING_SHEET "--exclude-drawing-sheet"
 #define ARG_PAGE_SIZE "--page-size-mode"
-#define ARG_DRILL_SHAPE_OPTION "--drill-shape-opt"
 
 
 CLI::PCB_EXPORT_SVG_COMMAND::PCB_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND( "svg" )
@@ -62,6 +59,10 @@ CLI::PCB_EXPORT_SVG_COMMAND::PCB_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND(
             .help( UTF8STDSTR( _( ARG_BLACKANDWHITE_DESC ) ) )
             .flag();
 
+    m_argParser.add_argument( "--sp", ARG_SKETCH_PADS_ON_FAB_LAYERS )
+            .help( UTF8STDSTR( _( ARG_SKETCH_PADS_ON_FAB_LAYERS_DESC ) ) )
+            .flag();
+
     m_argParser.add_argument( ARG_PAGE_SIZE )
             .help( UTF8STDSTR( _( "Set page sizing mode (0 = page with frame and title block, 1 = "
                                 "current page size, 2 = board area only)" ) ) )
@@ -74,8 +75,7 @@ CLI::PCB_EXPORT_SVG_COMMAND::PCB_EXPORT_SVG_COMMAND() : PCB_EXPORT_BASE_COMMAND(
             .flag();
 
     m_argParser.add_argument( ARG_DRILL_SHAPE_OPTION )
-            .help( UTF8STDSTR( _( "Set pad/via drill shape option (0 = no shape, 1 = "
-                                  "small shape, 2 = actual shape)" ) ) )
+            .help( UTF8STDSTR( _( ARG_DRILL_SHAPE_OPTION_DESC ) ) )
             .scan<'i', int>()
             .default_value( 2 )
             .metavar( "SHAPE_OPTION" );
@@ -94,6 +94,7 @@ int CLI::PCB_EXPORT_SVG_COMMAND::doPerform( KIWAY& aKiway )
     svgJob->m_blackAndWhite = m_argParser.get<bool>( ARG_BLACKANDWHITE );
     svgJob->m_pageSizeMode = m_argParser.get<int>( ARG_PAGE_SIZE );
     svgJob->m_negative = m_argParser.get<bool>( ARG_NEGATIVE );
+    svgJob->m_sketchPadsOnFabLayers = m_argParser.get<bool>( ARG_SKETCH_PADS_ON_FAB_LAYERS );
     svgJob->m_drillShapeOption = m_argParser.get<int>( ARG_DRILL_SHAPE_OPTION );
     svgJob->m_drawingSheet = m_argDrawingSheet;
 
diff --git a/pcbnew/dialogs/panel_pcbnew_color_settings.cpp b/pcbnew/dialogs/panel_pcbnew_color_settings.cpp
index 1de7e972b8..d97448a937 100644
--- a/pcbnew/dialogs/panel_pcbnew_color_settings.cpp
+++ b/pcbnew/dialogs/panel_pcbnew_color_settings.cpp
@@ -106,6 +106,7 @@ std::string g_previewBoard =
         "      (plotreference true)\n"
         "      (plotvalue true)\n"
         "      (plotinvisibletext false)\n"
+        "      (plotpadnumbers false)\n"
         "      (sketchpadsonfab false)\n"
         "      (subtractmaskfromsilk false)\n"
         "      (outputformat 1)\n"
diff --git a/pcbnew/exporters/export_svg.cpp b/pcbnew/exporters/export_svg.cpp
index 9a64b59791..630f759bbb 100644
--- a/pcbnew/exporters/export_svg.cpp
+++ b/pcbnew/exporters/export_svg.cpp
@@ -20,7 +20,6 @@
 
 #include "board.h"
 #include "locale_io.h"
-#include "pcb_plot_params.h"
 #include "export_svg.h"
 #include "pcbplot.h"
 #include "pgm_base.h"
@@ -34,6 +33,12 @@ bool EXPORT_SVG::Plot( BOARD* aBoard, const PCB_PLOT_SVG_OPTIONS& aSvgPlotOption
 
     plot_opts.SetPlotFrameRef( aSvgPlotOptions.m_plotFrame );
 
+    if( aSvgPlotOptions.m_sketchPadsOnFabLayers )
+    {
+        plot_opts.SetSketchPadsOnFabLayers( true );
+        plot_opts.SetPlotPadNumbers( true );
+    }
+
     // Adding drill marks, for copper layers
     if( ( LSET( aSvgPlotOptions.m_printMaskLayer ) & LSET::AllCuMask() ).any() )
     {
diff --git a/pcbnew/exporters/export_svg.h b/pcbnew/exporters/export_svg.h
index 71ab30bc79..21dcb005ab 100644
--- a/pcbnew/exporters/export_svg.h
+++ b/pcbnew/exporters/export_svg.h
@@ -34,6 +34,7 @@ struct PCB_PLOT_SVG_OPTIONS
     int m_pageSizeMode;
 
     LSEQ m_printMaskLayer;
+    bool m_sketchPadsOnFabLayers;
 
     // How holes in pads/vias are plotted:
     // 0 = no hole, 1 = small shape, 2 = actual shape
diff --git a/pcbnew/pcb_plot_params.cpp b/pcbnew/pcb_plot_params.cpp
index f995347241..3d8773bb41 100644
--- a/pcbnew/pcb_plot_params.cpp
+++ b/pcbnew/pcb_plot_params.cpp
@@ -118,6 +118,7 @@ PCB_PLOT_PARAMS::PCB_PLOT_PARAMS()
     m_plotFPText                 = true;
     m_plotInvisibleText          = false;
     m_sketchPadsOnFabLayers      = false;
+    m_plotPadNumbers             = false;
     m_subtractMaskFromSilk       = false;
     m_format                     = PLOT_FORMAT::GERBER;
     m_mirror                     = false;
@@ -244,12 +245,10 @@ void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter,
     KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotreference", m_plotReference );
     KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotvalue", m_plotValue );
     KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotfptext", m_plotFPText );
-    KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotinvisibletext",
-                              m_plotInvisibleText );
-    KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "sketchpadsonfab",
-                              m_sketchPadsOnFabLayers );
-    KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "subtractmaskfromsilk",
-                              m_subtractMaskFromSilk );
+    KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotinvisibletext", m_plotInvisibleText );
+    KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "sketchpadsonfab", m_sketchPadsOnFabLayers );
+    KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "plotpadnumbers", m_plotPadNumbers );
+    KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "subtractmaskfromsilk", m_subtractMaskFromSilk );
     aFormatter->Print( aNestLevel+1, "(outputformat %d)\n", static_cast<int>( m_format ) );
     KICAD_FORMAT::FormatBool( aFormatter, aNestLevel + 1, "mirror", m_mirror );
     aFormatter->Print( aNestLevel+1, "(drillshape %d)\n", (int)m_drillMarks );
@@ -359,6 +358,9 @@ bool PCB_PLOT_PARAMS::IsSameAs( const PCB_PLOT_PARAMS &aPcbPlotParams ) const
     if( m_sketchPadsOnFabLayers != aPcbPlotParams.m_sketchPadsOnFabLayers )
         return false;
 
+    if( m_plotPadNumbers != aPcbPlotParams.m_plotPadNumbers )
+        return false;
+
     if( m_subtractMaskFromSilk != aPcbPlotParams.m_subtractMaskFromSilk )
         return false;
 
@@ -630,6 +632,10 @@ void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams )
             aPcbPlotParams->m_sketchPadsOnFabLayers= parseBool();
             break;
 
+        case T_plotpadnumbers:
+            aPcbPlotParams->m_plotPadNumbers = parseBool();
+            break;
+
         case T_subtractmaskfromsilk:
             aPcbPlotParams->m_subtractMaskFromSilk = parseBool();
             break;
diff --git a/pcbnew/pcb_plot_params.h b/pcbnew/pcb_plot_params.h
index 5efaa3faff..2f695cd04c 100644
--- a/pcbnew/pcb_plot_params.h
+++ b/pcbnew/pcb_plot_params.h
@@ -71,6 +71,9 @@ public:
     void        SetPlotMode( OUTLINE_MODE aPlotMode ) { m_plotMode = aPlotMode; }
     OUTLINE_MODE GetPlotMode() const { return m_plotMode; }
 
+    void        SetPlotPadNumbers( bool aFlag ) { m_plotPadNumbers = aFlag; }
+    bool        GetPlotPadNumbers() const { return m_plotPadNumbers; }
+
     void        SetDXFPlotPolygonMode( bool aFlag ) { m_DXFPolygonMode = aFlag; }
     bool        GetDXFPlotPolygonMode() const { return m_DXFPolygonMode; }
 
@@ -203,6 +206,7 @@ private:
 
     bool            m_skipNPTH_Pads;    /// Used to disable NPTH pads plotting on copper layers
     OUTLINE_MODE    m_plotMode;         /// FILLED or SKETCH for filled objects.
+    bool            m_plotPadNumbers;   /// Plot pad numbers when sketching pads on fab layers
     DRILL_MARKS     m_drillMarks;       /// Holes can be not plotted, have a small mark, or be
                                         ///   plotted in actual size
     PLOT_TEXT_MODE  m_textMode;
diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp
index a7ca7cfc38..171a237f74 100644
--- a/pcbnew/pcbnew_jobs_handler.cpp
+++ b/pcbnew/pcbnew_jobs_handler.cpp
@@ -438,6 +438,7 @@ int PCBNEW_JOBS_HANDLER::JobExportSvg( JOB* aJob )
     svgPlotOptions.m_pageSizeMode = aSvgJob->m_pageSizeMode;
     svgPlotOptions.m_printMaskLayer = aSvgJob->m_printMaskLayer;
     svgPlotOptions.m_plotFrame = aSvgJob->m_plotDrawingSheet;
+    svgPlotOptions.m_sketchPadsOnFabLayers = aSvgJob->m_sketchPadsOnFabLayers;
     svgPlotOptions.m_drillShapeOption = aSvgJob->m_drillShapeOption;
 
     if( aJob->IsCli() )
@@ -571,6 +572,12 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob )
     plotOpts.SetBlackAndWhite( aPdfJob->m_blackAndWhite );
     plotOpts.SetNegative( aPdfJob->m_negative );
 
+    if( aPdfJob->m_sketchPadsOnFabLayers )
+    {
+        plotOpts.SetSketchPadsOnFabLayers( true );
+        plotOpts.SetPlotPadNumbers( true );
+    }
+
     switch( aPdfJob->m_drillShapeOption )
     {
         default:
@@ -1246,12 +1253,12 @@ int PCBNEW_JOBS_HANDLER::doFpExportSvg( JOB_FP_EXPORT_SVG* aSvgJob, const FOOTPR
     svgPlotOptions.m_mirror = false;
     svgPlotOptions.m_pageSizeMode = 2; // board bounding box
     svgPlotOptions.m_printMaskLayer = aSvgJob->m_printMaskLayer;
+    svgPlotOptions.m_sketchPadsOnFabLayers = aSvgJob->m_sketchPadsOnFabLayers;
     svgPlotOptions.m_plotFrame = false;
 
     if( !EXPORT_SVG::Plot( brd.get(), svgPlotOptions ) )
         m_reporter->Report( _( "Error creating svg file" ) + wxS( "\n" ), RPT_SEVERITY_ERROR );
 
-
     return CLI::EXIT_CODES::OK;
 }
 
diff --git a/pcbnew/pcbplot.h b/pcbnew/pcbplot.h
index ac29755b61..c32d3ae939 100644
--- a/pcbnew/pcbplot.h
+++ b/pcbnew/pcbplot.h
@@ -102,6 +102,8 @@ public:
      */
     void PlotPad( const PAD* aPad, const COLOR4D& aColor, OUTLINE_MODE aPlotMode );
 
+    void PlotPadNumber( const PAD* aPad, const COLOR4D& aColor );
+
     /**
      * Plot items like text and graphics but not tracks and footprints.
      */
diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp
index 1460ee35c6..85d50b8208 100644
--- a/pcbnew/plot_board_layers.cpp
+++ b/pcbnew/plot_board_layers.cpp
@@ -333,6 +333,14 @@ void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
                     color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
             }
 
+            if( sketchPads &&
+                    ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
+                      ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
+            {
+                if( aPlotOpt.GetPlotPadNumbers() )
+                    itemplotter.PlotPadNumber( pad, color );
+            }
+
             VECTOR2I margin;
             int width_adj = 0;
 
diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp
index 7da9be2d16..7acdcba493 100644
--- a/pcbnew/plot_brditems_plotter.cpp
+++ b/pcbnew/plot_brditems_plotter.cpp
@@ -72,6 +72,73 @@ COLOR4D BRDITEMS_PLOTTER::getColor( int aLayer ) const
 }
 
 
+void BRDITEMS_PLOTTER::PlotPadNumber( const PAD* aPad, const COLOR4D& aColor )
+{
+    wxString padNumber = UnescapeString( aPad->GetNumber() );
+
+    if( padNumber.IsEmpty() )
+        return;
+
+    BOX2I    padBBox = aPad->GetBoundingBox();
+    VECTOR2I position = padBBox.Centre();
+    VECTOR2I padsize = padBBox.GetSize();
+
+    if( aPad->GetShape() == PAD_SHAPE::CUSTOM )
+    {
+        // See if we have a number box
+        for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives() )
+        {
+            if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::RECTANGLE )
+            {
+                position = primitive->GetCenter();
+                RotatePoint( position, aPad->GetOrientation() );
+                position += aPad->ShapePos();
+
+                padsize.x = abs( primitive->GetBotRight().x - primitive->GetTopLeft().x );
+                padsize.y = abs( primitive->GetBotRight().y - primitive->GetTopLeft().y );
+
+                break;
+            }
+        }
+    }
+
+    if( aPad->GetShape() != PAD_SHAPE::CUSTOM )
+    {
+        // Don't allow a 45° rotation to bloat a pad's bounding box unnecessarily
+        int limit = KiROUND( std::min( aPad->GetSize().x, aPad->GetSize().y ) * 1.1 );
+
+        if( padsize.x > limit && padsize.y > limit )
+        {
+            padsize.x = limit;
+            padsize.y = limit;
+        }
+    }
+
+    TEXT_ATTRIBUTES textAttrs;
+
+    if( padsize.x < ( padsize.y * 0.95 ) )
+    {
+        textAttrs.m_Angle = ANGLE_90;
+        std::swap( padsize.x, padsize.y );
+    }
+
+    // approximate the size of the pad number text:
+    // We use a size for at least 3 chars, to give a good look even for short numbers
+    int tsize = KiROUND( padsize.x / std::max( PrintableCharCount( padNumber ), 3 ) );
+    tsize = std::min( tsize, padsize.y );
+
+    // enforce a max size
+    tsize = std::min( tsize, pcbIUScale.mmToIU( 5.0 ) );
+
+    textAttrs.m_Size = VECTOR2I( tsize, tsize );
+
+    // use a somewhat spindly font to go with the outlined pads
+    textAttrs.m_StrokeWidth = KiROUND( tsize / 12.0 );
+
+    m_plotter->PlotText( position, aColor, padNumber, textAttrs );
+}
+
+
 void BRDITEMS_PLOTTER::PlotPad( const PAD* aPad, const COLOR4D& aColor, OUTLINE_MODE aPlotMode )
 {
     VECTOR2I     shape_pos = aPad->ShapePos();