diff --git a/src/init.cpp b/src/init.cpp
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1471,7 +1471,7 @@
     if (IsArgSet("-minrelaytxfee")) {
         Amount n(0);
         auto parsed = ParseMoney(GetArg("-minrelaytxfee", ""), n);
-        if (!parsed || Amount(0) == n)
+        if (!parsed)
             return InitError(
                 AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
         // High fee check is done afterward in CWallet::ParameterInteraction()
diff --git a/src/miner.h b/src/miner.h
--- a/src/miner.h
+++ b/src/miner.h
@@ -6,6 +6,7 @@
 #ifndef BITCOIN_MINER_H
 #define BITCOIN_MINER_H
 
+#include "policy/policy.h"
 #include "primitives/block.h"
 #include "txmempool.h"
 
@@ -134,7 +135,7 @@
 
     // Configuration parameters for the block size
     uint64_t nMaxGeneratedBlockSize;
-    CFeeRate blockMinFeeRate;
+    CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
 
     // Information on the current status of the block
     uint64_t nBlockSize;
@@ -161,6 +162,7 @@
     CreateNewBlock(const CScript &scriptPubKeyIn);
 
     uint64_t GetMaxGeneratedBlockSize() const { return nMaxGeneratedBlockSize; }
+    void SetBlockMinTxFee(const Amount blockmintxfee);
 
 private:
     // utility functions
diff --git a/src/miner.cpp b/src/miner.cpp
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -80,6 +80,10 @@
     return nNewTime - nOldTime;
 }
 
+void BlockAssembler::SetBlockMinTxFee(const Amount blockmintxfee) {
+    blockMinFeeRate = CFeeRate(blockmintxfee);
+}
+
 static uint64_t ComputeMaxGeneratedBlockSize(const Config &config,
                                              const CBlockIndex *pindexPrev) {
     // Block resource limits
@@ -106,9 +110,7 @@
     if (IsArgSet("-blockmintxfee")) {
         Amount n(0);
         ParseMoney(GetArg("-blockmintxfee", ""), n);
-        blockMinFeeRate = CFeeRate(n);
-    } else {
-        blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
+        SetBlockMinTxFee(n);
     }
 
     LOCK(cs_main);
diff --git a/src/policy/policy.h b/src/policy/policy.h
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -22,7 +22,7 @@
 static const uint64_t DEFAULT_BLOCK_PRIORITY_PERCENTAGE = 5;
 /** Default for -blockmintxfee, which sets the minimum feerate for a transaction
  * in blocks created by mining code **/
-static const Amount DEFAULT_BLOCK_MIN_TX_FEE(1000);
+static const Amount DEFAULT_BLOCK_MIN_TX_FEE(0);
 /** The maximum size for transactions we're willing to relay/mine */
 static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
 /** Maximum number of signature check operations in an IsStandard() P2SH script
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -3,7 +3,6 @@
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include "miner.h"
-
 #include "chainparams.h"
 #include "coins.h"
 #include "config.h"
@@ -86,12 +85,40 @@
 
     GlobalConfig config;
 
+    // test 0 fee transaction is included in a block with
+    // default configuration.
+    blockMinFeeRate = CFeeRate(Amount(0));
+
+    // Test that a medium fee transaction will be selected after a higher fee
+    // rate package with a low fee rate parent.
+    CMutableTransaction tx;
+    tx.vin.resize(1);
+    tx.vin[0].scriptSig = CScript() << OP_1;
+    tx.vin[0].prevout.hash = txFirst[0]->GetId();
+    tx.vin[0].prevout.n = 0;
+    tx.vout.resize(1);
+    tx.vout[0].nValue = Amount(5000000000LL);
+    // This tx has a low fee: 1000 satoshis.
+    // Save this txid for later use.
+    uint256 zeroFeeTx = tx.GetId();
+    mempool.addUnchecked(
+        zeroFeeTx,
+        entry.Fee(Amount(0)).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+
+    std::unique_ptr<CBlockTemplate> pblocktemplate =
+        BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey);
+    BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == zeroFeeTx);
+
     // these 3 tests assume blockprioritypercentage is 0.
     config.SetBlockPriorityPercentage(0);
 
+    // the following tests assume that minimum fee rate is 1000 satoshi per kB.
+    BlockAssembler ba(config, chainparams);
+    ba.SetBlockMinTxFee(Amount(1000));
+    blockMinFeeRate = CFeeRate(Amount(1000));
+
     // Test that a medium fee transaction will be selected after a higher fee
     // rate package with a low fee rate parent.
-    CMutableTransaction tx;
     tx.vin.resize(1);
     tx.vin[0].scriptSig = CScript() << OP_1;
     tx.vin[0].prevout.hash = txFirst[0]->GetId();
@@ -125,8 +152,7 @@
                                             .SpendsCoinbase(false)
                                             .FromTx(tx));
 
-    std::unique_ptr<CBlockTemplate> pblocktemplate =
-        BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = ba.CreateNewBlock(scriptPubKey);
     BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == hashParentTx);
     BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == hashHighFeeTx);
     BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == hashMediumFeeTx);
@@ -147,8 +173,7 @@
     tx.vout[0].nValue = Amount(5000000000LL - 1000 - 50000) - feeToUse;
     uint256 hashLowFeeTx = tx.GetId();
     mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx));
-    pblocktemplate =
-        BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = ba.CreateNewBlock(scriptPubKey);
     // Verify that the free tx and the low fee tx didn't get selected.
     for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) {
         BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashFreeTx);
@@ -164,8 +189,7 @@
     hashLowFeeTx = tx.GetId();
     mempool.addUnchecked(hashLowFeeTx,
                          entry.Fee(feeToUse + Amount(2)).FromTx(tx));
-    pblocktemplate =
-        BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = ba.CreateNewBlock(scriptPubKey);
     BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == hashFreeTx);
     BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == hashLowFeeTx);
 
@@ -189,8 +213,7 @@
     uint256 hashLowFeeTx2 = tx.GetId();
     mempool.addUnchecked(hashLowFeeTx2,
                          entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
-    pblocktemplate =
-        BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = ba.CreateNewBlock(scriptPubKey);
 
     // Verify that this tx isn't selected.
     for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) {
@@ -204,8 +227,7 @@
     // 10k satoshi fee.
     tx.vout[0].nValue = Amount(100000000 - 10000);
     mempool.addUnchecked(tx.GetId(), entry.Fee(Amount(10000)).FromTx(tx));
-    pblocktemplate =
-        BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey);
+    pblocktemplate = ba.CreateNewBlock(scriptPubKey);
     BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == hashLowFeeTx2);
 }
 
diff --git a/src/validation.h b/src/validation.h
--- a/src/validation.h
+++ b/src/validation.h
@@ -56,7 +56,7 @@
 /** Default for DEFAULT_WHITELISTFORCERELAY. */
 static const bool DEFAULT_WHITELISTFORCERELAY = true;
 /** Default for -minrelaytxfee, minimum relay fee for transactions */
-static const Amount DEFAULT_MIN_RELAY_TX_FEE(1000);
+static const Amount DEFAULT_MIN_RELAY_TX_FEE(0);
 //! -maxtxfee default
 static const Amount DEFAULT_TRANSACTION_MAXFEE(COIN / 10);
 //! Discourage users to set fees higher than this amount (in satoshis) per kB
@@ -139,8 +139,9 @@
 /** Additional block download timeout per parallel downloading peer (i.e. 5 min)
  */
 static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
-
-static const unsigned int DEFAULT_LIMITFREERELAY = 0;
+/** Continuously rate-limit free/priority transactions to
+ * limiterfreerelay*1000 bytes per minute. */
+static const unsigned int DEFAULT_LIMITFREERELAY = 20;
 static const bool DEFAULT_RELAYPRIORITY = true;
 static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
 /** Maximum age of our tip in seconds for us to be considered current for fee