diff --git a/dumux/nonlinear/newtonsolver.hh b/dumux/nonlinear/newtonsolver.hh
index 82f9eca3de8b4fe84564362b67d6c6630fe32759..9a101fabbdbf980566eeefcf3615327a9a1ca171 100644
--- a/dumux/nonlinear/newtonsolver.hh
+++ b/dumux/nonlinear/newtonsolver.hh
@@ -168,8 +168,8 @@ public:
     { maxSteps_ = maxSteps; }
 
     /*!
-     * \brief Run the newton method to solve a non-linear system.
-     *        Does time step control when the newton fails to converge
+     * \brief Run the Newton method to solve a non-linear system.
+     *        Does time step control when the Newton fails to converge
      */
     template<class TimeLoop>
     void solve(SolutionVector& uCurrentIter, TimeLoop& timeLoop,
@@ -214,7 +214,7 @@ public:
     }
 
     /*!
-     * \brief Run the newton method to solve a non-linear system.
+     * \brief Run the Newton method to solve a non-linear system.
      *        The solver is responsible for all the strategic decisions.
      */
     void solve(SolutionVector& uCurrentIter, const std::unique_ptr<ConvergenceWriter>& convWriter = nullptr)
@@ -429,7 +429,7 @@ public:
             else
             {
                 // If we get here, the convergence criterion does not require
-                // additional residual evalutions. Thus, the grid variables have
+                // additional residual evaluations. Thus, the grid variables have
                 // not yet been updated to the new uCurrentIter.
                 assembler_->updateGridVariables(uCurrentIter);
             }
@@ -472,7 +472,7 @@ public:
         endIterMsgStream_.str("");
 
         // When the Newton iterations are done: ask the model to check whether it makes sense
-        // TODO: how do we realize this? -> do this here in the newton solver
+        // TODO: how do we realize this? -> do this here in the Newton solver
         // model_().checkPlausibility();
     }
 
@@ -525,11 +525,37 @@ public:
     virtual void newtonFail(SolutionVector& u) {}
 
     /*!
-     * \brief Called if the Newton method ended succcessfully
+     * \brief Called if the Newton method ended successfully
      * This method is called _after_ newtonEnd()
      */
     virtual void newtonSucceed()  {}
 
+    /*!
+     * \brief output statistics / report
+     */
+    void report(std::ostream& sout = std::cout) const
+    {
+        if (verbose_)
+            sout << '\n'
+                 << "Newton statistics\n"
+                 << "----------------------------------------------\n"
+                 << "-- Total Newton iterations:           " << totalWastedIter_ + totalSucceededIter_ << '\n'
+                 << "-- Total wasted Newton iterations:    " << totalWastedIter_ << '\n'
+                 << "-- Total succeeded Newton iterations: " << totalSucceededIter_ << '\n'
+                 << "-- Average iterations per solve:      " << std::setprecision(3) << double(totalSucceededIter_) / double(numConverged_) << '\n'
+                 << std::endl;
+    }
+
+    /*!
+     * \brief reset the statistics
+     */
+    void resetReport()
+    {
+        totalWastedIter_ = 0;
+        totalSucceededIter_ = 0;
+        numConverged_ = 0;
+    }
+
     /*!
      * \brief Suggest a new time-step size based on the old time-step
      *        size.
@@ -620,7 +646,7 @@ protected:
 private:
 
     /*!
-     * \brief Run the newton method to solve a non-linear system.
+     * \brief Run the Newton method to solve a non-linear system.
      *        The solver is responsible for all the strategic decisions.
      */
     bool solve_(SolutionVector& uCurrentIter, const std::unique_ptr<ConvergenceWriter>& convWriter = nullptr)
@@ -723,13 +749,17 @@ private:
             // tell solver we are done
             newtonEnd();
 
-            // reset state if newton failed
+            // reset state if Newton failed
             if (!newtonConverged())
             {
+                totalWastedIter_ += numSteps_;
                 newtonFail(uCurrentIter);
                 return false;
             }
 
+            totalSucceededIter_ += numSteps_;
+            numConverged_++;
+
             // tell solver we converged successfully
             newtonSucceed();
 
@@ -748,6 +778,8 @@ private:
         {
             if (verbose_)
                 std::cout << "Newton: Caught exception: \"" << e.what() << "\"\n";
+
+            totalWastedIter_ += numSteps_;
             newtonFail(uCurrentIter);
             return false;
         }
@@ -1108,6 +1140,11 @@ private:
     Scalar reassemblyMinThreshold_;
     Scalar reassemblyMaxThreshold_;
     Scalar reassemblyShiftWeight_;
+
+    // statistics for the optional report
+    std::size_t totalWastedIter_ = 0; //! Newton steps in solves that didn't converge
+    std::size_t totalSucceededIter_ = 0; //! Newton steps in solves that converged
+    std::size_t numConverged_ = 0; //! total number of converged solves
 };
 
 } // end namespace Dumux
diff --git a/test/porousmediumflow/2p/implicit/incompressible/test_2p_fv.cc b/test/porousmediumflow/2p/implicit/incompressible/test_2p_fv.cc
index ecb43e481412eb9564ce1262c55746156f217e24..daac6cf940a40adec59f2530569db2aa503375e8 100644
--- a/test/porousmediumflow/2p/implicit/incompressible/test_2p_fv.cc
+++ b/test/porousmediumflow/2p/implicit/incompressible/test_2p_fv.cc
@@ -200,6 +200,9 @@ int main(int argc, char** argv) try
 
     } while (!timeLoop->finished());
 
+    // output some Newton statistics
+    nonLinearSolver.report();
+
     timeLoop->finalize(leafGridView.comm());
 
     ////////////////////////////////////////////////////////////