diff --git a/dhcpd/dhcpd.go b/dhcpd/dhcpd.go
index 5719b0de..f95a9867 100644
--- a/dhcpd/dhcpd.go
+++ b/dhcpd/dhcpd.go
@@ -623,6 +623,12 @@ func (s *Server) AddStaticLease(l Lease) error {
 			s.leasesLock.Unlock()
 			return err
 		}
+	} else {
+		err := s.rmDynamicLeaseWithMAC(l.HWAddr)
+		if err != nil {
+			s.leasesLock.Unlock()
+			return err
+		}
 	}
 	s.leases = append(s.leases, &l)
 	s.reserveIP(l.IP, l.HWAddr)
@@ -649,6 +655,23 @@ func (s *Server) rmDynamicLeaseWithIP(ip net.IP) error {
 	return nil
 }
 
+// Remove a dynamic lease by IP address
+func (s *Server) rmDynamicLeaseWithMAC(mac net.HardwareAddr) error {
+	var newLeases []*Lease
+	for _, lease := range s.leases {
+		if bytes.Equal(lease.HWAddr, mac) {
+			if lease.Expiry.Unix() == leaseExpireStatic {
+				return fmt.Errorf("static lease with the same IP already exists")
+			}
+			s.unreserveIP(lease.IP)
+			continue
+		}
+		newLeases = append(newLeases, lease)
+	}
+	s.leases = newLeases
+	return nil
+}
+
 // Remove a lease
 func (s *Server) rmLease(l Lease) error {
 	var newLeases []*Lease
diff --git a/dhcpd/dhcpd_test.go b/dhcpd/dhcpd_test.go
index b41121a3..b08ffb86 100644
--- a/dhcpd/dhcpd_test.go
+++ b/dhcpd/dhcpd_test.go
@@ -20,6 +20,7 @@ func check(t *testing.T, result bool, msg string) {
 // Tests performed:
 // . Handle Discover message (lease reserve)
 // . Handle Request message (lease commit)
+// . Static leases
 func TestDHCP(t *testing.T) {
 	var s = Server{}
 	s.conf.DBFilePath = dbFilename
@@ -117,6 +118,7 @@ func TestDHCP(t *testing.T) {
 
 	s.reset()
 	testStaticLeases(t, &s)
+	testStaticLeaseReplaceByMAC(t, &s)
 
 	s.reset()
 	misc(t, &s)
@@ -126,15 +128,46 @@ func testStaticLeases(t *testing.T, s *Server) {
 	var err error
 	var l Lease
 	l.IP = []byte{1, 1, 1, 1}
+
+	l.HWAddr = []byte{1, 2, 3, 4, 5, 6}
+	s.leases = append(s.leases, &l)
+
+	// replace dynamic lease with a static (same IP)
 	l.HWAddr = []byte{2, 2, 3, 4, 5, 6}
 	err = s.AddStaticLease(l)
 	check(t, err == nil, "AddStaticLease")
 
-	ll := s.Leases(LeasesStatic)
-	check(t, len(ll) != 0 && bytes.Equal(ll[0].IP, []byte{1, 1, 1, 1}), "StaticLeases")
+	ll := s.Leases(LeasesAll)
+	assert.True(t, len(ll) == 1)
+	assert.True(t, bytes.Equal(ll[0].IP, []byte{1, 1, 1, 1}))
+	assert.True(t, bytes.Equal(ll[0].HWAddr, []byte{2, 2, 3, 4, 5, 6}))
+	assert.True(t, ll[0].Expiry.Unix() == leaseExpireStatic)
 
 	err = s.RemoveStaticLease(l)
-	check(t, err == nil, "RemoveStaticLease")
+	assert.True(t, err == nil)
+
+	ll = s.Leases(LeasesAll)
+	assert.True(t, len(ll) == 0)
+}
+
+func testStaticLeaseReplaceByMAC(t *testing.T, s *Server) {
+	var err error
+	var l Lease
+	l.HWAddr = []byte{1, 2, 3, 4, 5, 6}
+
+	l.IP = []byte{1, 1, 1, 1}
+	l.Expiry = time.Now().Add(time.Hour)
+	s.leases = append(s.leases, &l)
+
+	// replace dynamic lease with a static (same MAC)
+	l.IP = []byte{2, 1, 1, 1}
+	err = s.AddStaticLease(l)
+	assert.True(t, err == nil)
+
+	ll := s.Leases(LeasesAll)
+	assert.True(t, len(ll) == 1)
+	assert.True(t, bytes.Equal(ll[0].IP, []byte{2, 1, 1, 1}))
+	assert.True(t, bytes.Equal(ll[0].HWAddr, []byte{1, 2, 3, 4, 5, 6}))
 }
 
 // Small tests that don't require a static server's state