diff --git a/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java b/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
index 64de410..39b301d 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
@@ -270,4 +270,10 @@ public class FileAppender<E> extends WriterAppender<E> {
       super.writerWrite(s, flush);
     }
   }
+
+  @Override
+  protected void doRecreateWriter() throws IOException {
+      openFile(getFile());
+  }
+
 }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java b/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java
index bf4880b..83385b7 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java
@@ -14,6 +14,7 @@
 package ch.qos.logback.core;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
@@ -59,6 +60,16 @@ public class WriterAppender<E> extends UnsynchronizedAppenderBase<E> {
   private Writer writer;
 
   /**
+   * Number of consecutive errors in the appender
+   */
+  private int consecutiveErrors;
+
+  /**
+   * If writer has failed, retry after current time has passed this.
+   */
+  private long nextRetryTime;
+
+  /**
    * The default constructor does nothing.
    */
   public WriterAppender() {
@@ -150,6 +161,27 @@ public class WriterAppender<E> extends UnsynchronizedAppenderBase<E> {
   }
 
   /**
+   * Close the underlying {@link java.io.Writer}.
+   *
+   * @param writeHeader Should header be written before closing
+   */
+  protected void closeWriter(boolean writeHeader) {
+    if (this.writer != null) {
+      try {
+        if (writeHeader) {
+          // before closing we have to output out layout's footer
+          writeFooter();
+        }
+        this.writer.close();
+        this.writer = null;
+      } catch (IOException e) {
+        addStatus(new ErrorStatus("Could not close writer for WriterAppener.",
+            this, e));
+      }
+    }
+  }
+
+  /**
    * Returns an OutputStreamWriter when passed an OutputStream. The encoding
    * used will depend on the value of the <code>encoding</code> property. If
    * the encoding value is specified incorrectly the writer will be opened using
@@ -199,7 +231,6 @@ public class WriterAppender<E> extends UnsynchronizedAppenderBase<E> {
         }
 
       } catch (IOException ioe) {
-        this.started = false;
         addStatus(new ErrorStatus("Failed to write header for appender named ["
             + name + "].", this, ioe));
       }
@@ -222,7 +253,6 @@ public class WriterAppender<E> extends UnsynchronizedAppenderBase<E> {
           writerWrite(sb.toString(), true); // force flush
         }
       } catch (IOException ioe) {
-        this.started = false;
         addStatus(new ErrorStatus("Failed to write footer for appender named ["
             + name + "].", this, ioe));
       }
@@ -247,13 +277,52 @@ public class WriterAppender<E> extends UnsynchronizedAppenderBase<E> {
   }
 
   protected void writerWrite(String s, boolean flush) throws IOException {
+    try {
+      if (nextRetryTime > 0) {
+        long retryDelay = nextRetryTime - System.currentTimeMillis();
+        if (retryDelay > 0L) {
+          // Just return without returning error
+          return;
+        } else {
+          recreateWriter();
+        }
+      }
+      try {
+        writeAndFlush(s, flush);
+      } catch (IOException e) {
+        // Retry once instantly, better than discarding, especially in case of InterruptedIOException, because
+        // interruption is often used when shutting things down
+        recreateWriter();
+        writeAndFlush(s, flush);
+        if (e instanceof InterruptedIOException) {
+          Thread.currentThread().interrupt(); // Preserve interrupted status
+        }
+      }
+    } catch (IOException e) {
+        consecutiveErrors++;
+        calculateNextRetryTime();
+        throw e;
+    }
+    nextRetryTime = -1L;
+    consecutiveErrors = 0;
+  }
+
+  private void writeAndFlush(String s, boolean flush) throws IOException {
     this.writer.write(s);
     if (flush) {
       this.writer.flush();
     }
   }
 
-  /**
+  private void calculateNextRetryTime() {
+    long newRetryDelay = consecutiveErrors * consecutiveErrors * 1000L;
+    if (newRetryDelay > 15L * 60L * 1000L) {  // Limit to 15 min
+        newRetryDelay = 15L * 60L * 1000L;
+    }
+    nextRetryTime = System.currentTimeMillis() + newRetryDelay;
+  }
+
+/**
    * Actual writing occurs here.
    * <p>
    * Most subclasses of <code>WriterAppender</code> will need to override this
@@ -272,10 +341,17 @@ public class WriterAppender<E> extends UnsynchronizedAppenderBase<E> {
         writerWrite(output, this.immediateFlush);
       }
     } catch (IOException ioe) {
-      // as soon as an exception occurs, move to non-started state
       // and add a single ErrorStatus to the SM.
-      this.started = false;
       addStatus(new ErrorStatus("IO failure in appender", this, ioe));
     }
   }
+
+  protected final void recreateWriter() throws IOException {
+      closeWriter(false);
+      doRecreateWriter();
+  }
+
+  protected void doRecreateWriter() throws IOException  {
+  }
+
 }
diff --git a/logback-core/src/test/java/ch/qos/logback/core/appender/FileAppenderTest.java b/logback-core/src/test/java/ch/qos/logback/core/appender/FileAppenderTest.java
index 56e033b..7657926 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/appender/FileAppenderTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/appender/FileAppenderTest.java
@@ -17,7 +17,12 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.util.List;
 import java.util.Random;
 
@@ -130,4 +135,79 @@ public class FileAppenderTest extends AbstractAppenderTest<Object> {
     assertTrue(file.exists());
     assertTrue("failed to delete " + file.getAbsolutePath(), file.delete());
   }
+
+  @Test
+  public void testRecreation() throws IOException {
+    String filename = CoreTestConstants.OUTPUT_DIR_PREFIX + "temp.log";
+    new File(filename).delete();
+    FileAppender<Object> appender = new FileAppender<Object>();
+    appender.setLayout(new DummyLayout<Object>());
+    appender.setAppend(true);
+    appender.setFile(filename);
+    appender.setName("testRecreation");
+    appender.setContext(context);
+    appender.start();
+    appender.doAppend(new Object());
+
+    TestFileWriter writer = new TestFileWriter(filename, true);
+    appender.setWriter(writer);
+    appender.doAppend(new Object());
+    writer.close();
+    appender.doAppend(new Object());
+    try {
+        Thread.sleep(1500L); // Bit hacky, should be async...
+    } catch (InterruptedException e) {
+        throw new RuntimeException(e);
+    }
+    appender.doAppend(new Object());
+    appender.doAppend(new Object());
+    appender.stop();
+    System.out.println(context.getStatusManager().getCopyOfStatusList().toString());
+    context.getStatusManager().clear();
+
+    BufferedReader reader = new BufferedReader(new FileReader(filename));
+    // In succeeded case there should be five lines, one is discarded
+    assertTrue(reader.readLine() != null);
+    assertTrue(reader.readLine() != null);
+    assertTrue(reader.readLine() != null);
+    assertTrue(reader.readLine() != null);
+    assertTrue(reader.readLine() != null);
+    assertTrue(reader.readLine() == null);
+    reader.close();
+
+    // Test with InterruptedIOException
+    new File(filename).delete();
+    appender.start();
+    writer = new TestFileWriter(filename, true);
+    appender.setWriter(writer);
+    appender.doAppend(new Object());
+    writer.throwInterruptedIOException = true;
+    appender.doAppend(new Object());
+    reader = new BufferedReader(new FileReader(filename));
+    assertTrue(reader.readLine() != null);
+    assertTrue(reader.readLine() != null);
+    assertTrue(reader.readLine() == null);
+    reader.close();
+    System.out.println(context.getStatusManager().getCopyOfStatusList().toString());
+    Thread.interrupted(); // Clear interrupted status
+  }
+
+  private static class TestFileWriter extends FileWriter {
+
+    public boolean throwInterruptedIOException;
+
+    public TestFileWriter(String fileName, boolean append) throws IOException {
+        super(fileName, append);
+    }
+
+    @Override
+    public void write(String str) throws IOException {
+        if (throwInterruptedIOException) {
+            throw new InterruptedIOException("interrupted");
+        }
+        super.write(str);
+    }
+
+  }
+
 }
