The best way to understand the difference is with the help of an example.Below is the program to solve the classical producer consumer problem via semaphore.To provide mutual exclusion we genrally use a binary semaphore or mutex and to provide synchronization we use counting semaphore.
BufferSize = 3;
semaphore mutex = 1;              // used for mutual exclusion
semaphore empty = BufferSize;     // used for synchronization
semaphore full = 0;               // used for synchronization
Producer()
 {
  int widget;
   while (TRUE) {                  // loop forever
     make_new(widget);             // create a new widget to put in the buffer
     down(&empty);                 // decrement the empty semaphore
     down(&mutex);                 // enter critical section
     put_item(widget);             // put widget in buffer
     up(&mutex);                   // leave critical section
     up(&full);                    // increment the full semaphore
   }
 }
Consumer()
{
  int widget;
   while (TRUE) {                  // loop forever
     down(&full);                  // decrement the full semaphore
     down(&mutex);                 // enter critical section
     remove_item(widget);          // take a widget from the buffer
     up(&mutex);                   // leave critical section
     consume_item(widget);         // consume the item
  }
}
In the above code the mutex variable provides mutual exclusion(allow only one thread to access critical section) whereas full and the empty variable are used for synchonization(to aribtrate the access of shared resource among various thread).